python实现Leetcode树相关题目
1.重建二叉树
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。
思路:递归
1.直接递归左右子树的时候切分前序和中序。
pos是获取在中序遍历里根节点的位置
python里可以选择用dict存储,也可以用list.index(值)得到索引
# -*- coding:utf-8 -*-
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
# 返回构造的TreeNode根节点
def reConstructBinaryTree(self, pre, tin):
if len(pre)==0:
return None
# write code here
root=TreeNode(pre[0])
pos=tin.index(pre[0])
root.left=self.reConstructBinaryTree(pre[1:pos+1], tin[:pos])
root.right=self.reConstructBinaryTree(pre[pos+1:], tin[pos+1:])
return root
2.或者根据子树的根节点在前序中的位置/子树在中序中的左边界/子树在中序中的右边界
“pos-left+root+1”,其实就是右子树根节点=(中序根节点坐标-中序左边界)+先序根节点坐标+1,其中括号内=左子树长度。
left:中序左边界
right:中序右边界
root:前序根节点坐标
pos:中序根节点坐标
# -*- coding:utf-8 -*-
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def recur(root, left, right):
if left > right: return # 递归终止
node = TreeNode(pre[root]) # 建立根节点
pos = tin.index(pre[root]) # 划分根节点左子树右子树
node.left = recur(root + 1, left, pos - 1) # 开启左子树递归
node.right = recur(pos - left + root + 1, pos + 1, right) # 开启右子树递归
return node # 回溯返回根节点
return recur(0, 0, len(tin) - 1)
2.树的子结构
def isSubStructure(self, A: TreeNode, B: TreeNode) -> bool:
首先,树a或者树b为空均返回False
check检查b是否是a的子树||b是否是a左子树的子树||b是否是a右子树的子树(or)
def check(self,a,b):
在具体检查的时候:如a为空,匹配不上,b为空则可以匹配的上,当a,b均不为空的时候,检查a的根节点,left,right是否等于b的根节点,left,right.(and)
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def isSubStructure(self, A: TreeNode, B: TreeNode) -> bool:
def check(a,b):
if not b:return True
if not a:return False
return a.val==b.val and check(a.left,b.left) and check(a.right,b.right)
if not A or not B:return False
return check(A,B) or self.isSubStructure(A.left,B) or self.isSubStructure(A.right,B)
或者
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def check(self,a,b):
if not b :return True
if not a :return False
return a.val==b.val and self.check(a.left,b.left) and self.check(a.right,b.right)
def isSubStructure(self, A: TreeNode, B: TreeNode) -> bool:
if not A or not B: return False
return self.check(A,B) or self.isSubStructure(A.left,B) or self.isSubStructure(A.right,B)
注意:在check里需要注意,先判断有可能作为子树的b的情况,如果为空直接返回true了。如果先判断a的非空情况,如果a为空,有可能b也为空,但还没来得及判断就直接返回False了。
3.二叉树的镜像
题目:
镜像
思路1:递归
注意,如果是其他的语言需要暂存root.left再交换,python可以利用平行赋值的写法(即 a, b = b, a ),可省略暂存操作。其原理是先将等号右侧打包成元组 (b,a),再序列地分给等号左侧的 a, b 序列。
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def mirrorTree(self, root: TreeNode) -> TreeNode:
# 直接交换
if not root:return None
root.left,root.right=self.mirrorTree(root.right),self.mirrorTree(root.left)
return root
思路2:辅助stack
利用栈(或队列)遍历树的所有节点 node ,并交换每个 node 的左 / 右子节点。
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def mirrorTree(self, root: TreeNode) -> TreeNode:
if not root:return None
stack=[root]
while stack:
node=stack.pop()
if node.left:stack.append(node.left)
if node.right:stack.append(node.right)
node.left,node.right=node.right,node.left
return root
4.对称的二叉树
对称
思路:
isSymmetric(root) :
特例处理: 若根节点 root 为空,则直接返回 true。
返回值: 即 recur(root.left, root.right) ;
recur(L, R) :
终止条件:
当 L 和 R同时越过叶节点: 此树从顶至底的节点都对称,因此返回 true;
if not left and not right: return True
当 L或 R 中只有一个越过叶节点: 此树不对称,因此返回 false ;
当节点 L 值 != 节点 R 值: 此树不对称,因此返回 false;
if not left or not right or left.val!=right.val:return False
递推工作:
判断两节点 L.left 和 R.right 是否对称,即 recur(L.left, R.right) ;
判断两节点L.right 和 R.left 是否对称,即 recur(L.right, R.left) ;
返回值: 两对节点都对称时,才是对称树,因此用与逻辑符 &连接
return recur(left.left,right.right)and recur(left.right,right.left)
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def isSymmetric(self, root: TreeNode) -> bool:
def recur(left,right):
if not left and not right: return True
if not left or not right or left.val!=right.val:return False
return recur(left.left,right.right)and recur(left.right,right.left)
return recur(root.left,root.right) if root else True
5.层次遍历
5-1.输出层次遍历结果
用一个辅助队列
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def levelOrder(self, root: TreeNode) -> List[int]:
if not root:return []
res,queue=[],[root]
while queue:
node=queue.pop(0)
res.append(node.val)
if node.left:queue.append(node.left)
if node.right:queue.append(node.right)
return res
5-2.每层单独输出
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def levelOrder(self, root: TreeNode) -> List[List[int]]:
if not root:return []
res,queue=[],[root]
while queue:
temp=[]
for _ in range(len(queue)):
node=queue.pop(0)
temp.append(node.val)
if node.left: queue.append(node.left)
if node.right:queue.append(node.right)
res.append(temp)
return res
5-3.之字形输出
import collections
q=collections.deque()
q.append(xxx)
q.appendleft(xxxx)
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
#
#
# @param root TreeNode类
# @return int整型二维数组
import collections
class Solution:
def zigzagLevelOrder(self , root ):
# write code here
if not root:return []
queue,res=[root],[]
while queue:
temp=collections.deque()
for _ in range(len(queue)):
node=queue.pop(0)
if len(res)&1:
temp.appendleft(node.val)
else:
temp.append(node.val)
if node.left:queue.append(node.left)
if node.right:queue.append(node.right)
res.append(temp)
return res
6.二叉树的最大深度
求给定二叉树的最大深度,
最大深度是指树的根结点到最远叶子结点的最长路径上结点的数量。
思路1
DFS,递归
左右子树的最深深度+1即可
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
#DFS
def maxDepth(self, root: TreeNode) -> int:
if not root: return 0
return max(self.maxDepth(root.left),self.maxDepth(root.right))+1
思路2
BFS,层次遍历计算深度
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
#BFS
def maxDepth(self, root: TreeNode) -> int:
if not root:return 0
queue=[root]
depth=0
while queue:
for _ in range(len(queue)):
node=queue.pop(0)
if node.left:queue.append(node.left)
if node.right:queue.append(node.right)
depth+=1
return depth
7-1.和为target的路径
解题思路:
先序遍历: 按照 “根、左、右” 的顺序,遍历树的所有节点。
路径记录: 在先序遍历中,记录从根节点到当前节点的路径。当路径为 ① 根节点到叶节点形成的路径 且 ② 各节点值的和等于目标值 sum 时,将此路径加入结果列表。
**注意:**值得注意的是,记录路径时若直接执行 res.append(path) ,则是将 path 对象加入了 res ;后续 path 改变时, res 中的 path 对象也会随之改变。
正确做法:res.append(list(path)) ,相当于复制了一个 path 并加入到 res 。
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
#
#
# @param root TreeNode类
# @param sum int整型
# @return int整型二维数组
#
class Solution:
def pathSum(self , root , sum ):
res,path=[],[]
def recur(root,sum):
if not root:return
path.append(root.val)
sum-=root.val
if sum==0 and not root.left and not root.right:
res.append(list(path))
recur(root.left,sum)
recur(root.right,sum)
path.pop()
recur(root,sum)
return res
7-2 所有路径和
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
#
#
# @param root TreeNode类
# @return int整型
#
class Solution:
def sumNumbers(self , root ):
def recur(root,sum):
if not root:return 0
sum=sum*10+root.val
if not root.left and not root.right:
return sum
return recur(root.left,sum)+recur(root.right, sum)
sum=0
return recur(root,sum)
8.二叉搜索树的第k个节点
思路:二叉搜索树如果按照【右,根,左】顺序取,则从大到小排,取第k-1个值即可
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def kthLargest(self, root: TreeNode, k: int) -> int:
res=[]
def reverse_zx(root):
if not root:return
reverse_zx(root.right)
res.append(root.val)
reverse_zx(root.left)
reverse_zx(root)
return res[k-1]
9. 最近公共祖先
9-1. 二叉搜索树最近公共祖先
本题给定了两个重要条件:① 树为 二叉搜索树 ,② 树的所有节点的值都是 唯一 的。根据以上条件,可方便地判断 p,q 与 root的子树关系,即:
若 root.val < p.val,则 p 在 root 右子树 中;
若 root.val > p.val,则 p在 root 左子树 中;
若 root.val = p.val,则 p 和 root指向 同一节点 。
思路:
循环搜索: 当节点 root 为空时跳出;
当 p, q都在 root的 右子树 中,则遍历至 root.right ;
否则,当 p, q 都在 rootroot 的 左子树 中,则遍历至 root.left;
否则,说明找到了 最近公共祖先 ,跳出。
返回值: 最近公共祖先 root 。
class Solution:
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
if p.val > q.val: p, q = q, p # 保证 p.val < q.val
while root:
if root.val < p.val: # p,q 都在 root 的右子树中
root = root.right # 遍历至右子节点
elif root.val > q.val: # p,q 都在 root 的左子树中
root = root.left # 遍历至左子节点
else: break
return root
递归也可
class Solution:
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
if root.val < p.val and root.val < q.val:
return self.lowestCommonAncestor(root.right, p, q)
if root.val > p.val and root.val > q.val:
return self.lowestCommonAncestor(root.left, p, q)
return root
9-2. 二叉树的最近公共祖先
输出节点or输出节点值
考虑通过递归对二叉树进行后序遍历,当遇到节点 p或 q时返回。从底至顶回溯,当节点 p, q 在节点 root 的异侧时,节点 root即为最近公共祖先,则向上返回 root。
输出节点
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def lowestCommonAncestor(self, root: TreeNode, p: TreeNode, q: TreeNode) -> TreeNode:
if not root or root==p or q==root: return root
left=self.lowestCommonAncestor(root.left,p,q)
right=self.lowestCommonAncestor(root.right,p,q)
if not left: return right
if not right: return left
return root
输出节点值
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
#
#
# @param root TreeNode类
# @param o1 int整型
# @param o2 int整型
# @return int整型
#
class Solution:
def lowestCommonAncestor(self , root , o1 , o2 ):
if not root:return -1
if o1==root.val or o2==root.val:return root.val
left=self.lowestCommonAncestor(root.left, o1, o2)
right=self.lowestCommonAncestor(root.right, o1, o2)
if left==-1:return right
if right==-1: return left
return root.val
2021-03 未完待续