1. 二叉树深度探索:从基础遍历到高级应用
作为一名经历过多次算法面试的老兵,我深知二叉树在技术面试中的核心地位。今天要分享的是二叉树系列中承上启下的关键内容,这些知识点不仅是BAT等大厂高频考点,更是构建复杂算法思维的基石。记得我第一次面试时,就因为在层序遍历卡壳而错失机会,后来通过系统训练才真正掌握其中门道。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 核心算法原理与实现
2.1 层序遍历(Level Order Traversal)
层序遍历是二叉树算法中最具实用价值的遍历方式之一,其核心在于使用队列这种数据结构来实现广度优先搜索(BFS)。具体实现时需要注意:
python复制from collections import deque
def levelOrder(root):
if not root:
return []
queue = deque([root])
result = []
while queue:
level_size = len(queue)
current_level = []
for _ in range(level_size):
node = queue.popleft()
current_level.append(node.val)
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
result.append(current_level)
return result
这个实现有几个关键点:
- 使用双端队列(deque)而非普通列表,因为popleft()操作时间复杂度为O(1)
- 在每层开始前记录当前队列长度,确保准确区分不同层级的节点
- 时间复杂度O(n),空间复杂度O(n),n为节点数量
实际面试中,面试官常会要求手写层序遍历代码,建议将这段代码背熟并理解每个细节
2.2 翻转二叉树(Invert Binary Tree)
翻转二叉树看似简单,却是检验递归理解的经典题目。最优雅的解法是采用后序遍历:
python复制def invertTree(root):
if not root:
return None
# 先递归处理子树
left = invertTree(root.left)
right = invertTree(root.right)
# 再交换左右子树
root.left, root.right = right, left
return root
这个解法的时间复杂度同样是O(n),空间复杂度取决于递归深度,最坏情况下(树退化为链表)为O(n)
注意:有些面试官会故意问"为什么不用前序遍历",其实前序遍历也可以,但后序遍历的思维更符合"先解决子问题"的递归思想
3. 对称二叉树判断技巧
判断二叉树是否对称是考察递归思维的绝佳题目。关键点在于定义一个新的递归函数来比较两棵树:
python复制def isSymmetric(root):
if not root:
return True
return compare(root.left, root.right)
def compare(left, right):
if not left and not right:
return True
if not left or not right:
return False
if left.val != right.val:
return False
return compare(left.left, right.right) and compare(left.right, right.left)
这个解法有几个易错点:
- 需要单独处理空树情况
- 比较时要考虑四种可能的节点组合情况
- 递归比较时是左子树的左节点与右子树的右节点比较
4. 二叉树深度与高度计算
4.1 最大深度计算
二叉树的最大深度可以通过简单的递归实现:
python复制def maxDepth(root):
if not root:
return 0
return 1 + max(maxDepth(root.left), maxDepth(root.right))
4.2 最小深度计算
最小深度的计算要更谨慎,因为必须确保是到叶子节点的路径:
python复制def minDepth(root):
if not root:
return 0
if not root.left and not root.right:
return 1
if not root.left:
return 1 + minDepth(root.right)
if not root.right:
return 1 + minDepth(root.left)
return 1 + min(minDepth(root.left), minDepth(root.right))
常见错误:直接像最大深度那样取min值,这样会错误计算只有单边子树的情况
5. 完全二叉树节点计数
对于完全二叉树的节点计数,可以利用其特性进行优化:
python复制def countNodes(root):
if not root:
return 0
left_depth = right_depth = 0
left = right = root
while left:
left_depth += 1
left = left.left
while right:
right_depth += 1
right = right.right
if left_depth == right_depth:
return (1 << left_depth) - 1
return 1 + countNodes(root.left) + countNodes(root.right)
这个算法的时间复杂度可以优化到O(logN * logN),利用了完全二叉树的性质:
- 先计算左右两侧的深度
- 如果深度相同,可直接用公式计算节点数
- 否则递归计算
6. 平衡二叉树判断
判断平衡二叉树需要同时计算高度和判断平衡:
python复制def isBalanced(root):
def height(node):
if not node:
return 0
left_height = height(node.left)
right_height = height(node.right)
if left_height == -1 or right_height == -1 or abs(left_height - right_height) > 1:
return -1
return 1 + max(left_height, right_height)
return height(root) != -1
这个实现巧妙地在计算高度的同时判断平衡性,通过返回-1表示不平衡,避免了重复计算
7. 二叉树路径问题
7.1 所有路径输出
输出二叉树所有根到叶子的路径:
python复制def binaryTreePaths(root):
def dfs(node, path, res):
if not node:
return
path.append(str(node.val))
if not node.left and not node.right:
res.append("->".join(path))
dfs(node.left, path, res)
dfs(node.right, path, res)
path.pop()
res = []
dfs(root, [], res)
return res
7.2 路径总和检查
检查是否存在路径和等于给定值:
python复制def hasPathSum(root, targetSum):
if not root:
return False
if not root.left and not root.right:
return root.val == targetSum
remaining = targetSum - root.val
return hasPathSum(root.left, remaining) or hasPathSum(root.right, remaining)
8. 构造二叉树问题
8.1 从中序和后序遍历序列构造
python复制def buildTree(inorder, postorder):
if not inorder or not postorder:
return None
root_val = postorder[-1]
root = TreeNode(root_val)
idx = inorder.index(root_val)
root.left = buildTree(inorder[:idx], postorder[:idx])
root.right = buildTree(inorder[idx+1:], postorder[idx:-1])
return root
8.2 从前序和中序遍历序列构造
python复制def buildTree(preorder, inorder):
if not preorder or not inorder:
return None
root_val = preorder[0]
root = TreeNode(root_val)
idx = inorder.index(root_val)
root.left = buildTree(preorder[1:idx+1], inorder[:idx])
root.right = buildTree(preorder[idx+1:], inorder[idx+1:])
return root
关键点:确定左右子树在两个序列中的对应区间,前序/后序用于找根节点,中序用于区分左右子树
9. 二叉搜索树操作
9.1 验证二叉搜索树
python复制def isValidBST(root):
def helper(node, lower=float('-inf'), upper=float('inf')):
if not node:
return True
val = node.val
if val <= lower or val >= upper:
return False
return helper(node.left, lower, val) and helper(node.right, val, upper)
return helper(root)
9.2 二叉搜索树中的搜索
python复制def searchBST(root, val):
if not root:
return None
if root.val == val:
return root
elif val < root.val:
return searchBST(root.left, val)
else:
return searchBST(root.right, val)
10. 最近公共祖先问题
10.1 普通二叉树的LCA
python复制def lowestCommonAncestor(root, p, q):
if not root or root == p or root == q:
return root
left = lowestCommonAncestor(root.left, p, q)
right = lowestCommonAncestor(root.right, p, q)
if left and right:
return root
return left if left else right
10.2 二叉搜索树的LCA
python复制def lowestCommonAncestor(root, p, q):
while root:
if p.val < root.val and q.val < root.val:
root = root.left
elif p.val > root.val and q.val > root.val:
root = root.right
else:
return root
return None
11. 二叉树修剪与删除
11.1 修剪二叉搜索树
python复制def trimBST(root, low, high):
if not root:
return None
if root.val < low:
return trimBST(root.right, low, high)
if root.val > high:
return trimBST(root.left, low, high)
root.left = trimBST(root.left, low, high)
root.right = trimBST(root.right, low, high)
return root
11.2 删除二叉搜索树中的节点
python复制def deleteNode(root, key):
if not root:
return None
if key < root.val:
root.left = deleteNode(root.left, key)
elif key > root.val:
root.right = deleteNode(root.right, key)
else:
if not root.left:
return root.right
if not root.right:
return root.left
min_node = findMin(root.right)
root.val = min_node.val
root.right = deleteNode(root.right, min_node.val)
return root
def findMin(node):
while node.left:
node = node.left
return node
12. 序列化与反序列化
12.1 二叉树的序列化
python复制def serialize(root):
def helper(node):
if node:
vals.append(str(node.val))
helper(node.left)
helper(node.right)
else:
vals.append('#')
vals = []
helper(root)
return ' '.join(vals)
12.2 二叉树的反序列化
python复制def deserialize(data):
def helper():
val = next(vals)
if val == '#':
return None
node = TreeNode(int(val))
node.left = helper()
node.right = helper()
return node
vals = iter(data.split())
return helper()
13. 二叉树与链表转换
13.1 二叉树展开为链表
python复制def flatten(root):
if not root:
return None
flatten(root.left)
flatten(root.right)
left = root.left
right = root.right
root.left = None
root.right = left
p = root
while p.right:
p = p.right
p.right = right
14. 实战技巧与注意事项
-
递归思维训练:二叉树问题大多适合递归解决,要培养"相信递归函数能解决子问题"的思维模式
-
边界条件检查:永远先检查root是否为None,这是二叉树问题的常见陷阱
-
遍历顺序选择:
- 前序:根→左→右(适合自上而下处理)
- 中序:左→根→右(BST常用)
- 后序:左→右→根(适合自下而上处理)
-
空间复杂度优化:递归解法通常有O(h)的空间复杂度(h为树高),对于极度不平衡的树可能退化为O(n)
-
迭代与递归转换:掌握如何将递归算法改写为迭代形式,特别是使用栈模拟递归
-
测试用例设计:
- 空树
- 单节点树
- 完全左斜/右斜树
- 普通平衡树
- 大规模随机树
-
调试技巧:
- 可视化打印树结构
- 使用小例子手动模拟递归过程
- 添加详细的日志输出递归路径
-
性能优化方向:
- 避免重复计算(如添加记忆化)
- 利用二叉树性质剪枝(如BST的范围限制)
- 迭代替代递归减少栈空间
-
常见错误:
- 忘记处理空指针
- 混淆节点值与节点引用
- 错误计算树高/深度
- 在修改树结构时丢失引用
-
进阶学习路径:
- 学习各种平衡二叉树的实现(AVL、红黑树)
- 理解B树/B+树在数据库中的应用
- 探索树形DP问题
- 研究线段树、字典树等特殊树结构
