1. 题目解析与核心思路
515题"在每个树行中找最大值"是力扣上一道经典的二叉树遍历问题。题目要求我们找出二叉树每一层中的最大值,并以列表形式返回。例如对于二叉树:
code复制 1
/ \
3 2
/ \ \
5 3 9
需要返回[1,3,9],因为第一层最大值是1,第二层是3,第三层是9。
1.1 问题本质分析
这道题考察的核心能力是二叉树的层序遍历(BFS)和简单数据处理。与常规BFS不同之处在于,我们需要在遍历每一层时记录当前层的最大值,而不是简单地输出所有节点值。
1.2 算法选择考量
解决这个问题主要有两种思路:
- BFS层序遍历:使用队列逐层遍历,适合直观理解树的层级结构
- DFS深度优先遍历:通过记录深度信息,也能获取每层节点
经过实际测试,BFS方案在代码简洁性和运行效率上都更优。DFS虽然也能解决问题,但需要额外维护深度信息,代码复杂度较高。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. BFS标准解法实现
2.1 基础BFS框架
标准的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
2.2 修改为最大值版本
基于标准模板,我们只需要做两处修改:
- 将收集当前层所有节点改为记录最大值
- 在每层循环开始时初始化最大值变量
最终实现代码:
python复制from collections import deque
def largestValues(root):
if not root:
return []
queue = deque([root])
result = []
while queue:
level_size = len(queue)
level_max = float('-inf')
for _ in range(level_size):
node = queue.popleft()
level_max = max(level_max, node.val)
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
result.append(level_max)
return result
2.3 复杂度分析
- 时间复杂度:O(N),每个节点被访问一次
- 空间复杂度:O(W),W是树的最大宽度(队列最大长度)
3. DFS替代方案实现
虽然BFS是更直观的解法,但DFS在某些场景下也有其优势。以下是DFS的实现方式:
3.1 DFS递归实现
python复制def largestValues(root):
result = []
def dfs(node, depth):
if not node:
return
if depth == len(result):
result.append(node.val)
else:
result[depth] = max(result[depth], node.val)
dfs(node.left, depth+1)
dfs(node.right, depth+1)
dfs(root, 0)
return result
3.2 DFS与BFS对比
| 特性 | BFS | DFS |
|---|---|---|
| 空间复杂度 | O(W) 最宽层的节点数 | O(H) 树的高度 |
| 适用场景 | 需要按层处理时 | 树很深但宽度不大时 |
| 代码复杂度 | 中等 | 较简单 |
| 内存占用 | 队列存储当前层所有节点 | 递归栈存储当前路径 |
4. 边界条件与异常处理
在实际编码中,需要特别注意以下边界情况:
4.1 空树处理
python复制if not root:
return []
4.2 单节点树
输入:[1]
输出:[1]
4.3 完全不平衡树
输入:
code复制 1
/
2
/
3
输出:[1,2,3]
4.4 节点值为负数
需要正确初始化level_max为-inf而非0
5. 语言特性优化
不同编程语言可以利用各自特性优化实现:
5.1 Python优化版
python复制def largestValues(root):
result = []
level = [root] if root else []
while level:
result.append(max(node.val for node in level))
level = [child for node in level for child in (node.left, node.right) if child]
return result
5.2 Java实现
java复制class Solution {
public List<Integer> largestValues(TreeNode root) {
List<Integer> result = new ArrayList<>();
if (root == null) return result;
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()) {
int size = queue.size();
int levelMax = Integer.MIN_VALUE;
for (int i = 0; i < size; i++) {
TreeNode node = queue.poll();
levelMax = Math.max(levelMax, node.val);
if (node.left != null) queue.offer(node.left);
if (node.right != null) queue.offer(node.right);
}
result.add(levelMax);
}
return result;
}
}
5.3 C++实现
cpp复制class Solution {
public:
vector<int> largestValues(TreeNode* root) {
vector<int> result;
if (!root) return result;
queue<TreeNode*> q;
q.push(root);
while (!q.empty()) {
int size = q.size();
int level_max = INT_MIN;
for (int i = 0; i < size; ++i) {
TreeNode* node = q.front();
q.pop();
level_max = max(level_max, node->val);
if (node->left) q.push(node->left);
if (node->right) q.push(node->right);
}
result.push_back(level_max);
}
return result;
}
};
6. 常见错误与调试技巧
6.1 典型错误案例
错误1:忘记处理空树
python复制def largestValues(root): # 缺少空树判断
queue = [root]
result = []
...
错误2:最大值初始化不当
python复制level_max = 0 # 应该用-inf,否则无法处理负值
错误3:层数统计错误
python复制for _ in range(len(queue)): # 应该在循环外先获取queue长度
node = queue.pop(0) # pop(0)是O(n)操作,应该用deque
...
6.2 调试技巧
-
打印调试法:在每层循环结束时打印当前层最大值
python复制print(f"Level {len(result)} max: {level_max}") -
可视化树结构:使用二叉树可视化工具验证输入
python复制from binarytree import build print(build([1,3,2,5,3,None,9])) -
单元测试:准备多种测试用例
python复制test_cases = [ ([1,3,2,5,3,None,9], [1,3,9]), ([1], [1]), ([], []), ([1,None,2], [1,2]) ]
7. 进阶思考与扩展
7.1 相关问题延伸
- 找每层最小值:只需将max改为min
- 找每层平均值:计算sum/len
- 找每层众数:使用字典统计频率
7.2 性能优化方向
对于特别大的树:
- 并行处理:不同层可以并行计算
- 迭代深化DFS:结合BFS和DFS优点
- 内存优化:对于极宽树,DFS可能更省内存
7.3 实际应用场景
- 图像金字塔处理:类似分层最大值操作
- 游戏AI决策树:评估不同深度的最佳策略
- 网络路由算法:分层查找最优路径
8. 刷题方法论
8.1 二叉树问题解题框架
- 明确遍历顺序:前序、中序、后序 or 层序
- 确定递归参数:当前节点、附加信息(深度等)
- 处理边界条件:空节点、单节点等
- 选择数据结构:栈、队列、哈希表等
8.2 力扣刷题建议
- 同类题目集中练习:如连续刷多道二叉树题目
- 多种解法实现:至少掌握递归和迭代两种写法
- 总结模板:整理常见问题的代码模板
8.3 代码风格建议
- 统一命名规范:如
level_max而非max_val - 添加必要注释:特别是边界条件处理
- 函数单一职责:避免一个函数做多件事
在实际刷题过程中,我发现先画出树的结构图能显著提高解题效率。对于层序遍历问题,在纸上模拟队列操作往往能帮助快速发现逻辑错误。另外,建议将标准BFS模板背熟,这样遇到变种题目时能快速基于模板修改。
