1. 问题背景与理解
"1302 层数最深叶子节点的和"这个题目乍看有些抽象,但实际上是二叉树遍历的一个经典变种问题。作为一名经常处理树形结构的开发者,我第一眼就意识到这是一个需要在遍历过程中动态维护深度信息的题目。
简单来说,我们需要找到二叉树中最深的那一层叶子节点,然后计算这些叶子节点值的总和。听起来容易,但在实际编码中会遇到几个关键挑战:
- 如何准确判断当前节点是否属于最深层次?
- 当发现更深的层次时,如何重置之前的累加结果?
- 对于不同遍历方式(DFS/BFS)的实现差异在哪里?
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 解法思路分析
2.1 深度优先搜索(DFS)方案
DFS是最直观的解法,通过递归遍历可以自然地获取深度信息。我的实现思路是:
-
维护两个全局变量:
max_depth记录当前已知的最大深度total记录当前最深层的节点值之和
-
递归函数参数:
- 当前节点
node - 当前深度
current_depth
- 当前节点
-
递归逻辑:
- 当遇到叶子节点时:
- 如果
current_depth > max_depth,则更新max_depth并重置total - 如果
current_depth == max_depth,则累加到total
- 如果
- 递归处理左右子树
- 当遇到叶子节点时:
python复制class Solution:
def deepestLeavesSum(self, root: TreeNode) -> int:
self.max_depth = 0
self.total = 0
def dfs(node, depth):
if not node:
return
if not node.left and not node.right:
if depth > self.max_depth:
self.max_depth = depth
self.total = node.val
elif depth == self.max_depth:
self.total += node.val
return
dfs(node.left, depth + 1)
dfs(node.right, depth + 1)
dfs(root, 0)
return self.total
2.2 广度优先搜索(BFS)方案
BFS的层序遍历特性使其更适合处理这类层级相关问题。实现要点:
- 使用队列进行标准BFS遍历
- 在每一层遍历开始时,记录当前队列长度(即该层节点数)
- 维护一个变量存储当前层的节点值之和
- 当遍历完成时,最后一层的和就是我们需要的结果
python复制from collections import deque
class Solution:
def deepestLeavesSum(self, root: TreeNode) -> int:
if not root:
return 0
queue = deque([root])
level_sum = 0
while queue:
level_sum = 0
level_size = len(queue)
for _ in range(level_size):
node = queue.popleft()
level_sum += node.val
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
return level_sum
3. 算法复杂度对比
| 方法 | 时间复杂度 | 空间复杂度 | 适用场景 |
|---|---|---|---|
| DFS | O(N) | O(H) | 树较平衡时更优 |
| BFS | O(N) | O(W) | 需要知道每层信息时更优 |
其中:
- N 是节点总数
- H 是树的高度
- W 是树的最大宽度
4. 边界条件与测试用例
在实际编码中,有几个边界情况需要特别注意:
- 空树情况:直接返回0
- 单节点树:返回根节点值
- 所有叶子都在同一层:相当于求最后一层所有节点和
- 不平衡树:确保算法在左右子树高度差很大时仍能正确工作
我建议的测试用例:
python复制# 用例1:常规情况
# 1
# / \
# 2 3
# / \ \
# 4 5 6
# / \
# 7 8
# 预期结果:15 (7+8)
# 用例2:所有叶子在同一层
# 1
# / \
# 2 3
# 预期结果:5 (2+3)
# 用例3:单节点
# 1
# 预期结果:1
# 用例4:空树
# 预期结果:0
5. 实际编码中的优化技巧
5.1 DFS的优化实现
原始DFS使用了类成员变量,这在某些编程语言中可能不够优雅。我们可以通过将信息包装在返回值中来实现纯函数式的DFS:
python复制def deepestLeavesSum(self, root: TreeNode) -> int:
def dfs(node):
if not node:
return (0, 0) # (depth, sum)
if not node.left and not node.right:
return (1, node.val)
left_depth, left_sum = dfs(node.left)
right_depth, right_sum = dfs(node.right)
if left_depth > right_depth:
return (left_depth + 1, left_sum)
elif left_depth < right_depth:
return (right_depth + 1, right_sum)
else:
return (left_depth + 1, left_sum + right_sum)
return dfs(root)[1]
5.2 BFS的内存优化
标准BFS实现需要存储整层节点,对于非常宽的树可能消耗较多内存。可以采用逐层处理的方式,每次只保留下一层的节点:
python复制def deepestLeavesSum(self, root: TreeNode) -> int:
if not root:
return 0
current_level = [root]
while current_level:
next_level = []
level_sum = 0
for node in current_level:
level_sum += node.val
if node.left:
next_level.append(node.left)
if node.right:
next_level.append(node.right)
if not next_level: # 已经是最后一层
return level_sum
current_level = next_level
6. 不同语言实现要点
6.1 Java实现注意事项
在Java中,DFS的递归实现需要注意:
- 对于大型树可能引发栈溢出
- 可以使用栈来模拟递归过程
java复制// BFS实现示例
public int deepestLeavesSum(TreeNode root) {
if (root == null) return 0;
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
int sum = 0;
while (!queue.isEmpty()) {
sum = 0;
int size = queue.size();
for (int i = 0; i < size; i++) {
TreeNode node = queue.poll();
sum += node.val;
if (node.left != null) queue.offer(node.left);
if (node.right != null) queue.offer(node.right);
}
}
return sum;
}
6.2 JavaScript实现特点
JavaScript的函数式特性可以写出更简洁的DFS实现:
javascript复制function deepestLeavesSum(root) {
let maxDepth = 0, sum = 0;
function dfs(node, depth) {
if (!node) return;
if (!node.left && !node.right) {
if (depth > maxDepth) {
maxDepth = depth;
sum = node.val;
} else if (depth === maxDepth) {
sum += node.val;
}
return;
}
dfs(node.left, depth + 1);
dfs(node.right, depth + 1);
}
dfs(root, 0);
return sum;
}
7. 常见错误与调试技巧
7.1 易错点分析
- 深度计算错误:在DFS中容易混淆当前深度和最大深度的关系
- 重置逻辑错误:发现更深深度的叶子时忘记重置累加和
- BFS层处理错误:没有正确处理每层的边界,导致计算结果包含多层节点
- 空指针异常:没有检查节点是否为null就直接访问其属性
7.2 调试建议
- 打印遍历路径:在递归函数中加入深度和节点值的打印语句
- 可视化树结构:先画出树的结构图,手动计算预期结果
- 单步调试:使用调试器观察变量变化,特别是max_depth和total的变化
- 小规模测试:先用简单的3-4个节点的树测试,再扩展到复杂情况
8. 实际应用场景
这个问题虽然看起来是算法题,但其核心思想在实际开发中有广泛应用:
- 文件系统分析:计算最深目录中的文件总大小
- 组织架构处理:查找公司最底层员工的某些统计信息
- DOM树处理:分析网页中最深层元素的特定属性
- 游戏AI决策树:评估决策树最深层节点的得分情况
理解这个问题的解法,可以帮助我们在面对类似层级数据结构时快速找到解决方案。
