一句话总结
二叉树遍历是基础:前序(根左右)、中序(左根右,BST 有序)、后序(左右根,自底向上)、层序(BFS 队列)。高频题:最大深度(后序递归)、对称二叉树(双指针递归)、路径和(回溯)、最近公共祖先(后序遍历,左右子树各找到一个目标则当前为 LCA)。核心思想:递归 = 定义 + 终止条件 + 子问题。
初级理解
三种深度遍历(递归)
# 前序遍历:根 → 左 → 右
def preorder(root):
if not root: return
print(root.val) # 根
preorder(root.left) # 左
preorder(root.right) # 右
# 中序遍历:左 → 根 → 右(BST 得到有序序列)
def inorder(root):
if not root: return
inorder(root.left)
print(root.val)
inorder(root.right)
# 后序遍历:左 → 右 → 根(自底向上)
def postorder(root):
if not root: return
postorder(root.left)
postorder(root.right)
print(root.val)
层序遍历(BFS)
from collections import deque
def level_order(root):
if not root: return []
result = []
queue = deque([root])
while queue:
level = []
for _ in range(len(queue)): # 当前层节点数
node = queue.popleft()
level.append(node.val)
if node.left: queue.append(node.left)
if node.right: queue.append(node.right)
result.append(level)
return result
一句话总结:前中后序用递归/栈,层序用队列 BFS。
中级深入
迭代遍历(用栈模拟递归)
# 前序迭代(根左右 → 栈:右左)
def preorder_iter(root):
if not root: return []
result, stack = [], [root]
while stack:
node = stack.pop()
result.append(node.val)
if node.right: stack.append(node.right) # 先右
if node.left: stack.append(node.left) # 后左
return result
# 中序迭代(一路向左,再处理)
def inorder_iter(root):
result, stack = [], []
curr = root
while curr or stack:
while curr: # 一路向左
stack.append(curr)
curr = curr.left
curr = stack.pop()
result.append(curr.val)
curr = curr.right
return result
# 后序迭代(前序的逆序:根右左 → 反转 → 左右根)
def postorder_iter(root):
if not root: return []
result, stack = [], [root]
while stack:
node = stack.pop()
result.append(node.val)
if node.left: stack.append(node.left)
if node.right: stack.append(node.right)
return result[::-1] # 反转
最大深度(LeetCode 104)
# 后序递归(自底向上)
def max_depth(root):
if not root: return 0
left = max_depth(root.left)
right = max_depth(root.right)
return max(left, right) + 1
# BFS 层序
def max_depth_bfs(root):
if not root: return 0
depth = 0
queue = deque([root])
while queue:
depth += 1
for _ in range(len(queue)):
node = queue.popleft()
if node.left: queue.append(node.left)
if node.right: queue.append(node.right)
return depth
中级要点:迭代遍历用栈模拟;最大深度后序递归或 BFS 层数。
高级拓展
最近公共祖先(LeetCode 236)
def lowest_common_ancestor(root, p, q):
if not root or root == p or root == q:
return root
left = lowest_common_ancestor(root.left, p, q)
right = lowest_common_ancestor(root.right, p, q)
# 左右各找到一个 → 当前节点是 LCA
if left and right:
return root
# 只在一边找到 → 返回那一边
return left or right
# 原理:后序遍历,自底向上
# 如果 p 和 q 分别在左右子树 → root 是 LCA
# 如果 p 和 q 都在左子树 → 返回左子树的 LCA
# 如果 p 和 q 都在右子树 → 返回右子树的 LCA
对称二叉树(LeetCode 101)
def is_symmetric(root):
if not root: return True
return check(root.left, root.right)
def check(left, right):
if not left and not right: return True
if not left or not right: return False
return (left.val == right.val and
check(left.left, right.right) and # 外侧
check(left.right, right.left)) # 内侧
路径总和(LeetCode 112 + 113)
# 是否存在路径和等于 target
def has_path_sum(root, target):
if not root: return False
if not root.left and not root.right:
return root.val == target
return (has_path_sum(root.left, target - root.val) or
has_path_sum(root.right, target - root.val))
# 找出所有路径(回溯)
def path_sum(root, target):
result = []
def backtrack(node, target, path):
if not node: return
path.append(node.val)
if not node.left and not node.right and node.val == target:
result.append(path[:])
backtrack(node.left, target - node.val, path)
backtrack(node.right, target - node.val, path)
path.pop() # 回溯
backtrack(root, target, [])
return result
实战场景
场景:验证二叉搜索树(LeetCode 98)
# 方法1:中序遍历(BST 中序有序)
def is_valid_bst(root):
prev = float('-inf')
def inorder(node):
nonlocal prev
if not node: return True
if not inorder(node.left): return False
if node.val <= prev: return False
prev = node.val
return inorder(node.right)
return inorder(root)
# 方法2:递归范围判断
def is_valid_bst2(root):
def check(node, low, high):
if not node: return True
if node.val <= low or node.val >= high:
return False
return (check(node.left, low, node.val) and
check(node.right, node.val, high))
return check(root, float('-inf'), float('inf'))
面试模拟
面试官:二叉树的前中后序遍历,迭代怎么写?
你:前序:栈先压右再压左;中序:一路向左压栈,弹出处理后再处理右子树;后序:前序的"根右左"反转得到"左右根"。三种遍历都可以用栈模拟递归的调用栈。
面试官:最近公共祖先怎么找?
你:后序遍历自底向上。如果当前节点是 p 或 q 则返回;递归左右子树,如果左右各找到一个目标,当前节点就是 LCA;如果只在一边找到,返回那一边的结果。时间复杂度 O(n),空间 O(h)。