1. 项目概述:LeetCode面试经典150题精讲
作为一名经历过多次大厂面试的工程师,我深知算法题在技术面试中的分量。LeetCode面试经典150题集合了硅谷科技公司和国内一线互联网企业最高频的算法考点,其中二叉树相关题目占比超过20%,是面试官最青睐的考察方向之一。今天我们就以第53天(1.4节)的二叉树题目为例,深入解析这类题目的解题套路和实战技巧。
二叉树题目之所以成为面试常客,是因为它能同时考察候选人的数据结构基础、递归思维和边界处理能力。在实际开发中,二叉树的变体(如B+树)广泛应用于数据库索引,而遍历算法更是处理层级数据的基础。掌握这些题目不仅能通过面试,更能提升解决实际工程问题的能力。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 二叉树核心解题框架
2.1 二叉树遍历的三种基础范式
所有二叉树算法题都建立在三种基本遍历方式之上:
- 前序遍历(根-左-右):适合处理自上而下的问题
python复制def preorder(root):
if not root: return
print(root.val) # 处理当前节点
preorder(root.left) # 递归左子树
preorder(root.right) # 递归右子树
- 中序遍历(左-根-右):适合处理二叉搜索树(BST)相关问题
python复制def inorder(root):
if not root: return
inorder(root.left) # 递归左子树
print(root.val) # 处理当前节点
inorder(root.right) # 递归右子树
- 后序遍历(左-右-根):适合自底向上的计算
python复制def postorder(root):
if not root: return
postorder(root.left) # 递归左子树
postorder(root.right) # 递归右子树
print(root.val) # 处理当前节点
关键技巧:递归解法的时间复杂度通常是O(n),空间复杂度取决于树高,最坏情况下(斜树)为O(n)
2.2 层序遍历(BFS)的标准模板
当问题涉及层级关系或最短路径时,BFS是不二之选。以下是Python标准实现:
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
这个模板可以解决诸如「二叉树的右视图」、「锯齿形层序遍历」等变种题目。注意这里使用了队列的popleft()操作保证FIFO特性,时间复杂度同样是O(n)。
3. 高频面试题深度解析
3.1 题目104:二叉树的最大深度
这是最经典的递归应用题,两种解法各有优劣:
递归解法(后序遍历):
python复制def maxDepth(root):
if not root: return 0
return 1 + max(maxDepth(root.left), maxDepth(root.right))
BFS解法:
python复制def maxDepth(root):
if not root: return 0
queue = deque([root])
depth = 0
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
面试陷阱:面试官可能会追问两种方法的空间复杂度差异。递归解法在最坏情况下(树退化为链表)空间复杂度为O(n),而BFS的空间复杂度取决于最宽层的节点数。
3.2 题目101:对称二叉树
这道题考察对二叉树结构的理解,精妙的递归思路是:
python复制def isSymmetric(root):
def compare(left, right):
if not left and not right: return True
if not left or not right: return False
return left.val == right.val and \
compare(left.left, right.right) and \
compare(left.right, right.left)
return compare(root.left, root.right) if root else True
迭代解法则使用队列模拟递归过程:
python复制def isSymmetric(root):
if not root: return True
queue = deque([(root.left, root.right)])
while queue:
left, right = queue.popleft()
if not left and not right: continue
if not left or not right: return False
if left.val != right.val: return False
queue.append((left.left, right.right))
queue.append((left.right, right.left))
return True
3.3 题目105:从前序与中序遍历序列构造二叉树
这是考察递归思维的典型题目,关键在于定位根节点位置:
python复制def buildTree(preorder, inorder):
inorder_map = {val:idx for idx,val in enumerate(inorder)}
pre_idx = 0
def helper(left, right):
nonlocal pre_idx
if left > right: return None
root_val = preorder[pre_idx]
root = TreeNode(root_val)
pre_idx += 1
inorder_idx = inorder_map[root_val]
root.left = helper(left, inorder_idx-1)
root.right = helper(inorder_idx+1, right)
return root
return helper(0, len(inorder)-1)
工程实践:这种构造方法在实际开发中常用于重建二叉树结构,比如反序列化存储的树状数据。
4. 二叉树解题进阶技巧
4.1 递归转迭代的通用方法
当面试官要求避免递归时,可以用显式栈模拟递归过程。以前序遍历为例:
python复制def preorderTraversal(root):
if not root: return []
stack, result = [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
这种方法的优势在于避免了递归的栈溢出风险,适合处理深度很大的树结构。
4.2 莫里斯遍历(Morris Traversal)
一种空间复杂度O(1)的遍历方法,核心思想是利用叶子节点的空指针:
python复制def inorderTraversal(root):
curr = root
res = []
while curr:
if not curr.left:
res.append(curr.val)
curr = curr.right
else:
# 找到当前节点的前驱节点
pre = curr.left
while pre.right and pre.right != curr:
pre = pre.right
if not pre.right:
pre.right = curr # 建立线索
curr = curr.left
else:
pre.right = None # 拆除线索
res.append(curr.val)
curr = curr.right
return res
适用场景:当内存严格受限时(如嵌入式开发),这种算法能显著减少内存消耗。
5. 面试实战注意事项
-
白板编码规范:
- 先明确输入输出类型
- 写出函数签名和返回值
- 用注释标注算法思路
- 最后处理边界条件
-
复杂度分析要点:
- 二叉树问题时间复杂度通常是O(n)
- 空间复杂度要区分平均情况和最坏情况
- 能说出递归调用栈的最大深度
-
常见失误点:
- 忘记处理空节点(root为None的情况)
- 混淆节点值比较和节点对象比较
- 层序遍历时未记录当前层节点数
- 修改树结构时未保存原始指针
-
测试用例设计:
- 空树
- 单节点树
- 完全二叉树
- 斜树(全左或全右)
- 随机构造的普通树
6. 题目变种与延展思考
6.1 子树判断问题(题目572)
判断树B是否是树A的子树,关键在于双重递归:
python复制def isSubtree(root, subRoot):
if not subRoot: return True
if not root: return False
return isSameTree(root, subRoot) or \
isSubtree(root.left, subRoot) or \
isSubtree(root.right, subRoot)
def isSameTree(p, q):
if not p and not q: return True
if not p or not q: return False
return p.val == q.val and \
isSameTree(p.left, q.left) and \
isSameTree(p.right, q.right)
6.2 二叉搜索树验证(题目98)
利用中序遍历的升序特性:
python复制def isValidBST(root):
stack, prev = [], None
while stack or root:
while root:
stack.append(root)
root = root.left
root = stack.pop()
if prev and root.val <= prev.val:
return False
prev = root
root = root.right
return True
6.3 二叉树中的最大路径和(题目124)
后序遍历的典型应用:
python复制def maxPathSum(root):
max_sum = float('-inf')
def helper(node):
nonlocal max_sum
if not node: return 0
left_gain = max(helper(node.left), 0)
right_gain = max(helper(node.right), 0)
max_sum = max(max_sum, node.val + left_gain + right_gain)
return node.val + max(left_gain, right_gain)
helper(root)
return max_sum
在实际面试中,遇到二叉树问题时建议先明确遍历方式,再考虑递归或迭代实现。对于难题,可以从暴力解法开始逐步优化,同时注意和面试官保持沟通,解释你的思考过程。记住:清晰的解题思路比完美的代码更重要。
