重建二叉树
思路
用递归的方式解决:
- Root是preorder的首项,在inorder里面找到root对应的位置,即可以确定左右子树。
- 左子树的root是pre_root的下一项;依然根据root的位置确定root在左子树inorder的顺序,之后一直递归下去。
- 右子树的root是preorder中右子树的第一项:pre_root+1+i-in_left。根据这个递归下去。
代码
class Solution:
def buildTree(self, preorder: List[int], inorder: List[int]) -> TreeNode:
self.dic, self.po = {}, preorder
for i in range(len(inorder)):
self.dic[inorder[i]] = i
return self.recur(0, 0, len(inorder) - 1)
def recur(self, pre_root, in_left, in_right):
if in_left > in_right: return # 终止条件:中序遍历为空
root = TreeNode(self.po[pre_root]) # 建立当前子树的根节点
i = self.dic[self.po[pre_root]] # 搜索根节点在中序遍历中的索引,从而可对根节点、左子树、右子树完成划分。
root.left = self.recur(pre_root + 1, in_left, i - 1) # 开启左子树的下层递归
root.right = self.recur(i - in_left + pre_root + 1, i + 1, in_right) # 开启右子树的下层递归
return 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 buildTree(self, inorder: List[int], postorder: List[int]) -> TreeNode:
self.dic, self.po = {}, postorder
for i in range(len(inorder)):
self.dic[inorder[i]] = i
return self.recur(len(postorder)-1, 0, len(inorder)-1)
def recur(self, post_root, in_left, in_right):
if in_left>in_right : return None
# 找根节点
root_node = TreeNode(self.po[post_root])
if in_left == in_right:
return root_node
# 找根节点在inorder中的位置
i = self.dic[self.po[post_root]]
print(i)
# 递归
root_node.right = self.recur(post_root-1, i+1, in_right)
# 左子树考虑清楚,是post_root-(右子树的长度)-1
root_node.left = self.recur(post_root-in_right+i-1, in_left, i-1)
return root_node
剑指 Offer 26. 树的子结构
思路
经典的“匹配类二叉树问题”。有套路可循:
- 先匹配根节点
- 匹配根节点之后对子树进行匹配
在这道题中,写两个函数分别完成这两个功能:dfs 对子树进行匹配;isSubStructure为主函数,对应根节点的匹配。
代码
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def dfs(self, a, b):
if not b: return True
if not a: return False
else:
return a.val == b.val and self.dfs(a.left, b.left) and self.dfs(a.right, b.right)
def isSubStructure(self, A: TreeNode, B: TreeNode) -> bool:
if not A or not B: return False
return self.dfs(A, B) or self.isSubStructure(A.left, B) or self.isSubStructure(A.right, B)
思考
一道题解决一类题,我们可以用这个思路解决一系列“匹配类二叉树”的题目。
101. 对称二叉树
思路
同上
代码
class Solution:
def dfs(self, a, b):
if not a and not b: return True
elif not a or not b: return False
return a.val == b.val and self.dfs(a.left, b.right) and self.dfs(a.right, b.left)
def isSymmetric(self, root: TreeNode) -> bool:
if not root: return True
return self.dfs(root.left, root.right)
1367. 二叉树中的列表
思路
只是将其中一个树换成了链表,实际上还是匹配根节点,再匹配子树的套路。
代码
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def dfs(self, a, b):
if not a : return True
if not b : return False
return b.val == a.val and \
(self.dfs(a.next, b.left) or self.dfs(a.next, b.right))
def isSubPath(self, head: ListNode, root: TreeNode) -> bool:
if not root or not head: return False
return self.dfs(head, root) or self.isSubPath(head, root.left) or self.isSubPath(head, root.right)
572. 另一个树的子树
思路
同上
代码
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def dfs(self, s, t):
if not s and not t: return True
elif not s or not t: return False
return s.val == t.val and self.dfs(s.left, t.left) and self.dfs(s.right, t.right)
def isSubtree(self, s: TreeNode, t: TreeNode) -> bool:
if not s or not t: return False
return self.dfs(s, t) or self.isSubtree(s.left, t) or self.isSubtree(s.right, t)
剑指 Offer 27. 二叉树的镜像
思路
- 用递归的方法解决:在不None的情况下,新左右等于旧右左。
代码
# 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
剑指 Offer 32 - I. 从上到下打印二叉树
思路
- 用BFS的方式,即采用queue结构来保存,之后依次写入res,最后打印出来。相当直接。
代码
import queue
class Solution:
def levelOrder(self, root: TreeNode) -> List[int]:
if not root: return []
q = queue.deque()
res = []
q.append(root)
while q:
out = q.popleft()
res.append(out.val)
if out.left: q.append(out.left)
if out.right: q.append(out.right)
return res
思考
这里需要注意,queue库中,Queue是依靠List实现的,所以put和insert的平均读写时间是
O
(
n
)
O(n)
O(n). 而deque双向队列是
O
(
1
)
O(1)
O(1)。所以用Queue写会超时。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kG3sCswf-1601058243643)(evernotecid://BC7CFB48-5C18-439C-ADB2-AD1171DE2741/appyinxiangcom/18838120/ENResource/p670)]
剑指 Offer 32 - II. 从上到下打印二叉树 II
思路:
同上,不过有一点点改变:在每次循环中把val写入这一层的tmp list,最后append tmp
代码:
# 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, q = [], collections.deque()
q.append(root)
while q:
tmp = []
for _ in range(len(q)):
out = q.popleft()
if out.left: q.append(out.left)
if out.right: q.append(out.right)
tmp.append(out.val)
res.append(tmp)
return res
思考:
一定要把边界条件放在最开始考虑
剑指 Offer 32 - III. 从上到下打印二叉树 III
思路
同上,不过每奇数层做一个翻转操作。
代码
# 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, q = [], collections.deque()
l = 0
q.append(root)
while q:
tmp = []
for _ in range(len(q)):
out = q.popleft()
if out.left: q.append(out.left)
if out.right: q.append(out.right)
tmp.append(out.val)
if l%2 == 1:
print(tmp)
for p in range(len(tmp)):
tmp.insert(p, tmp.pop())
l += 1
res.append(tmp)
return res
剑指 Offer 34. 二叉树中和为某一值的路径
思路:
本问题是典型的二叉树方案搜索问题,使用回溯法解决,其包含 先序遍历 + 路径记录 两部分。
-
先序遍历: 按照 “根、左、右” 的顺序,遍历树的所有节点。
-
路径记录: 在先序遍历中,记录从根节点到当前节点的路径。当路径为 ① 根节点到叶节点形成的路径 且 ② 各节点值的和等于目标值 sum 时,将此路径加入结果列表。
算法流程:
pathSum(root, sum) 函数:
初始化: 结果列表 res ,路径列表 path 。
返回值: 返回 res 即可。
recur(root, tar) 函数:
递推参数: 当前节点 root ,当前目标值 tar 。
终止条件: 若节点 root 为空,则直接返回。
递推工作:
-
路径更新: 将当前节点值 root.val 加入路径 path ;
-
目标值更新: tar = tar - root.val(即目标值 tar 从 sum 减至 00 );
-
路径记录: 当 ① root 为叶节点 且 ② 路径和等于目标值 ,则将此路径 path 加入 res 。
-
先序遍历: 递归左 / 右子节点。
-
路径恢复: 向上回溯前,需要将当前节点从路径 path 中删除,即执行 path.pop() 。
代码:
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def pathSum(self, root: TreeNode, sum: int) -> List[List[int]]:
res,path = [],[]
dif = sum
def recur(root, dif):
if not root: return None
path.append(root.val)
dif -= root.val
if dif == 0 and not root.left and not root.right:
# 这里如果不用list强制构造新list,就会导致res里面加入的是path,是一直变化的。
res.append(list(path))
recur(root.left, dif)
recur(root.right, dif)
path.pop()
recur(root, dif)
return res
思考:
在def里面定义def,能够帮助理清思路。而且不用调用self,局部变量可以直接在内部函数里面调用。backtracking里面要注意,在路径恢复的时候要pop掉当前节点才能返回上一步。
剑指 Offer 54. 二叉搜索树的第k大节点
思路
- 一个特殊的性质:BST的inorder traversal是从小到大排列好的。
- 那么这道题就可以从inorder的逆序列。
代码
class Solution:
def kthLargest(self, root: TreeNode, k: int) -> int:
def dfs(root):
if not root: return
dfs(root.right)
if self.k == 0: return
self.k -= 1
if self.k == 0: self.res = root.val
dfs(root.left)
self.k = k
dfs(root)
return self.res
剑指 Offer 55 - I. 二叉树的深度
思路
- 第一个想到就是BFS,然后之前做的按层level print。可以输出这个res的长度。但非常不直接。
- 也可以用DFS:深度就等于当前节点左/右子树的深度最大值+1。
代码
BFS:
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def maxDepth(self, root: TreeNode) -> int:
if not root:
return 0
# bfs, queue
res, q = [], collections.deque()
q.append(root)
while q:
tmp = []
for _ in range(len(q)):
out = q.popleft()
tmp.append(out.val)
if out.left: q.append(out.left)
if out.right: q.append(out.right)
res.append(tmp)
return len(res)
DFS:
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def maxDepth(self, root: TreeNode) -> int:
if not root: return 0
return max(self.maxDepth(root.left), self.maxDepth(root.right))+1
剑指 Offer 55 - II. 平衡二叉树
思路:
- 可以用上面最大深度的function,先算出来左右子树的最大深度,再递归地判断当前是不是一个平衡二叉树。时间复杂度很高O(N*logn)
- 剪枝
代码
简单算法:
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def isBalanced(self, root: TreeNode) -> bool:
def get_depth(root):
if not root: return 0
return max(get_depth(root.left), get_depth(root.right))+1
if not root: return True
left_depth, right_depth= get_depth(root.left), get_depth(root.right)
if abs(left_depth - right_depth) <= 1:
return self.isBalanced(root.left) and self.isBalanced(root.right)
else: return False
剪枝算法:
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def isBalanced(self, root: TreeNode) -> bool:
def recur(root):
if not root: return 0
left = recur(root.left)
if left == -1: return -1
right = recur(root.right)
if right == -1: return -1
if abs(left-right) >1 : return -1
else : return max(left, right)+1
return recur(root) != -1
剑指 Offer 68 - I. 二叉搜索树的最近公共祖先
思路:
- 递归的方法解决:在以下三种情况下返回的是root值:
- p, q分别在root的两侧
- p是root
- q是root
- 那么当p,q都在右侧时,递归右子树;vice versa。
代码:
# 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':
p_val, q_val = p.val, q.val
if not root: return
if (root.val-p_val)*(root.val-q_val) <= 0:
return root
elif p_val > root.val and q_val > root.val:
return self.lowestCommonAncestor(root.right, p, q)
elif p_val < root.val and q_val < root.val:
return self.lowestCommonAncestor(root.left, p, q)
剑指 Offer 68 - II. 二叉树的最近公共祖先
思路:
- 用inorder遍历,得到的list可以判断左右子树的关系。那么就可以跟上一题一样,进行迭代。
代码
# 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: return None
in_list = []
dic = {}
def inorder(root):
if not root: return
inorder(root.left)
in_list.append(root.val)
inorder(root.right)
inorder(root)
for i in range(len(in_list)):
dic[in_list[i]] = i
p_c, q_c = dic[p.val], dic[q.val]
while root:
root_c = dic[root.val]
if (p_c - root_c)*(q_c - root_c) <= 0 : return root
if p_c<root_c and q_c < root_c : root = root.left
if p_c > root_c and q_c > root_c : root = root.right
389

被折叠的 条评论
为什么被折叠?



