LeetCode 剑指Offer 数据结构之 树 总结 Part2
经典问题
1)遍历
2)树深度
3)重建树
4)对称树
5)子树匹配
6)二叉查找树
遍历问题 补充
DFS(一般采用递归) 深度优先的遍历
在此补充非递归方式的三种遍历
先序遍历:
def bin_tree_pre_order_traverse1(root):
'''
利用1个栈实现
'''
res = []
s1 = []
s1.append(root)
while s1:
node = s1.pop()# 对于s1中每个要被访问的跟节点
res.append(node.val)# 先访问它本身(根)
# 压栈 右,左->下次循环时出栈 左 右,符合前序遍历
if node.right:
s1.append(node.right)
if node.left:
s1.append(node.left)
return res
中序遍历:
def bin_tree_in_order_traverse1(root):
'''
利用1个栈实现
'''
res = []
s1 = []
node = root# 根节点先不入栈 需要找到最左的节点
while node or s1:
if node:
s1.append(node)
node = node.left# 向左不停找
else:
# node 为空,走到叶子节点了
node = s1.pop()# 左边节点的根(最左节点)
res.append(node.val)# 入栈
node = node.right
return res
后序遍历:
def bin_tree_post_order_traverse1(root):
'''
利用两个栈实现
'''
s1 = []
s2 = []
s1.append(root)
res = []
while s1:
node = s1.pop()
s2.append(node)# 中进栈 右进栈 左进栈
if node.left:
s1.append(node.left)
if node.right:
s1.append(node.right)
while s2:# 反过来 左出,右出,中出
res.append(s2.pop().val)
return res
深度问题
对应题目编号:
剑指 Offer 55 - I
剑指 Offer 55 - II
求二叉树深度:
class Solution:
def maxDepth_DFS(self, root):
if not root:
return 0
return max(self.maxDepth_DFS(root.left), self.maxDepth_DFS(root.right)) + 1
def maxDepth_BFS(self, root):
if not root:
return 0
queue = [root]
res = 0
while queue:
tmp = []
for index in range(len(queue)):
nodei = queue[index]
if nodei.left:
tmp.append(nodei.left)
if nodei.right:
tmp.append(nodei.right)
queue = tmp # 转移到下一层
res += 1
return res
DFS的方式:通过递归达到底部叶子节点,从0开始返回开始计数!
树的深度是每一颗子树的左右根的深度最大值+1
BFS的方式:
特例处理: 当 root 为空,直接返回 深度 00 。
初始化: 队列 queue (加入根节点 root ),计数器 res = 0。
循环遍历: 当 queue 为空时跳出。
初始化一个空列表 tmp ,用于临时存储下一层节点;
遍历队列: 遍历 queue 中的各节点 node ,并将其左子节点和右子节点加入 tmp;
更新队列: 执行 queue = tmp ,将下一层节点赋值给 queue;
统计层数: 执行 res += 1 ,代表层数加 11;
返回值: 返回 res 即可。
判断是否是平衡树
class Solution:
def isBalanced(self, root):
def recur(root):
if not root: # 出口
return 0 # 正常递归穿过叶子节点 作为递归到底部叶子节点 开始计算深度 从0开始 特例空树也在这里
left = recur(root.left)
if left == -1: # 出口
return -1
right = recur(root.right)
if right == -1: # 出口
return -1
return max(left, right) + 1 if abs(left - right) <= 1 else -1
return recur(root) != -1
后序遍历 + 剪枝 (从底至顶)
思路是对二叉树做后序遍历,从底至顶返回子树深度,若判定某子树不是平衡树则 “剪枝” ,直接向上返回
总结:主要分几种情况可以触发剪枝
1:当节点root 左 / 右子树的深度差 > 2 :则返回 -1 不是平衡树
2:当左(右)子树深度为 -1 :代表此树的 左(右)子树 不是平衡树,因此剪枝,直接返回 -1
下一部分将继续总结重建树内容