二叉树最深层叶子节点和的递归与迭代解法
2026/9/16 12:37:16 网站建设 项目流程

1. 题目解析与解题思路

这道题目要求我们计算二叉树中最深层叶子节点的和。乍一看似乎很简单,但实际处理时需要同时考虑树的深度遍历和特定层级的节点统计。作为刚接触树结构的新手,我最初被这个看似简单的问题卡住了好几个小时。

1.1 问题核心理解

题目给出的二叉树结构定义如下:

struct TreeNode { int val; TreeNode *left; TreeNode *right; TreeNode() : val(0), left(nullptr), right(nullptr) {} TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} };

关键点在于:

  1. 需要先确定树的最大深度
  2. 然后收集所有位于该深度的叶子节点
  3. 最后将这些节点的值相加

1.2 解题思路选择

我最终选择了DFS(深度优先搜索)的递归解法,原因如下:

  • 递归天然适合处理树结构
  • DFS可以自然地跟踪当前节点的深度
  • 相比BFS(广度优先搜索)需要维护队列,DFS实现更简洁

2. 代码实现详解

2.1 最大深度计算

int maxDepth; // 定义最大深度 void getMaxDepth(TreeNode* root, int depth) { if(root == NULL) { // 递归终止条件 return; } if(maxDepth < depth) { maxDepth = depth; // 更新最大深度 } getMaxDepth(root->left, depth+1); // 递归左子树 getMaxDepth(root->right, depth+1); // 递归右子树 }

这段代码有几个关键点需要注意:

  1. maxDepth是类成员变量,用于在递归过程中保持状态
  2. 每次递归调用时,当前深度depth会+1
  3. 遇到空节点时直接返回,这是递归的终止条件

2.2 最深层节点求和

int sumMaxDepth(TreeNode* root, int depth) { if(root == NULL) { return 0; } if(maxDepth == depth) { return root->val; // 找到目标节点,返回其值 } return sumMaxDepth(root->left, depth+1) + sumMaxDepth(root->right, depth+1); }

这个函数的逻辑:

  1. 同样以空节点作为递归终止条件
  2. 当当前深度等于最大深度时,返回该节点的值
  3. 否则继续递归左右子树,并将结果相加

2.3 主函数整合

int deepestLeavesSum(TreeNode* root) { maxDepth = 0; getMaxDepth(root, 0); // 先计算最大深度 return sumMaxDepth(root, 0); // 再求和 }

主函数的执行顺序很重要:

  1. 必须先计算最大深度
  2. 然后才能基于这个深度求节点和

3. 关键知识点解析

3.1 递归在树结构中的应用

树是递归定义的天然结构,每个子树本身也是一棵树。这种自相似性使得递归成为处理树问题的利器。在本解法中,我们利用递归实现了:

  • 深度优先遍历
  • 深度信息的传递
  • 节点值的累加

3.2 递归函数的返回值处理

这里有一个很重要的细节:

  • getMaxDepth是void类型,通过修改成员变量maxDepth来传递结果
  • sumMaxDepth是int类型,通过返回值传递计算结果

这种差异反映了递归函数设计的两种常见模式:

  1. 通过参数或成员变量"向下"传递信息
  2. 通过返回值"向上"传递计算结果

4. 常见问题与优化思考

4.1 空树处理

当前代码已经考虑了空树的情况:

  • getMaxDepth遇到空节点直接返回,maxDepth保持初始值0
  • sumMaxDepth遇到空节点返回0,最终和为0

4.2 递归深度限制

对于极端不平衡的树(如退化成链表),递归可能导致栈溢出。这时可以考虑:

  1. 使用迭代代替递归
  2. 改用BFS实现
  3. 增加递归深度限制检查

4.3 时间复杂度分析

该算法的时间复杂度是O(n),其中n是节点数量,因为:

  • 计算最大深度需要遍历所有节点
  • 求和过程也需要遍历所有节点
  • 每个节点只被访问两次

空间复杂度取决于树的高度,最坏情况下是O(n)。

5. 代码优化建议

5.1 合并两次遍历

当前解法遍历了两次树,可以优化为一次遍历:

class Solution { public: int deepest = 0; int sum = 0; void dfs(TreeNode* node, int depth) { if(!node) return; if(depth > deepest) { deepest = depth; sum = node->val; } else if(depth == deepest) { sum += node->val; } dfs(node->left, depth+1); dfs(node->right, depth+1); } int deepestLeavesSum(TreeNode* root) { dfs(root, 0); return sum; } };

这个优化版本:

  1. 只遍历一次树
  2. 动态更新最大深度和对应节点和
  3. 减少了重复计算

5.2 迭代实现方案

对于不喜欢递归的开发者,可以用迭代实现:

int deepestLeavesSum(TreeNode* root) { if(!root) return 0; queue<TreeNode*> q; q.push(root); int sum = 0; while(!q.empty()) { int size = q.size(); sum = 0; // 重置当前层级的和 for(int i = 0; i < size; i++) { TreeNode* node = q.front(); q.pop(); sum += node->val; if(node->left) q.push(node->left); if(node->right) q.push(node->right); } } return sum; }

这个BFS实现:

  1. 按层级遍历树
  2. 最后一层自然就是最深层
  3. 不需要预先计算深度

6. 学习心得与总结

通过这道题目,我深刻理解了递归在树结构中的应用。几个关键收获:

  1. 递归终止条件必须明确,否则会导致无限递归
  2. 递归函数的返回值类型决定了如何处理子问题的结果
  3. 树的问题通常有多种解法(DFS/BFS,递归/迭代),各有优缺点
  4. 先理清思路再写代码,比直接动手调试效率高得多

对于树结构的练习,我的建议是:

  • 先掌握基本的遍历方式(前序、中序、后序)
  • 理解递归的工作原理
  • 多做练习题,从简单到复杂逐步提升

这道题目虽然让我纠结了很久,但通过不断调试和思考,最终不仅解决了问题,还对树结构和递归有了更深的理解。这种通过实际问题驱动学习的方式,效果比单纯看书要好得多。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询