## 题目地址(129. 求根到叶子节点数字之和) https://leetcode-cn.com/problems/sum-root-to-leaf-numbers/ ## 题目描述 ``` 给定一个二叉树,它的每个结点都存放一个 0-9 的数字,每条从根到叶子节点的路径都代表一个数字。 例如,从根到叶子节点路径 1->2->3 代表数字 123。 计算从根到叶子节点生成的所有数字之和。 说明: 叶子节点是指没有子节点的节点。 示例 1: 输入: [1,2,3] 1 / \ 2 3 输出: 25 解释: 从根到叶子节点路径 1->2 代表数字 12. 从根到叶子节点路径 1->3 代表数字 13. 因此,数字总和 = 12 + 13 = 25. 示例 2: 输入: [4,9,0,5,1] 4 / \ 9 0  / \ 5 1 输出: 1026 解释: 从根到叶子节点路径 4->9->5 代表数字 495. 从根到叶子节点路径 4->9->1 代表数字 491. 从根到叶子节点路径 4->0 代表数字 40. 因此,数字总和 = 495 + 491 + 40 = 1026. ``` ## 前置知识 - 递归 ## 公司 - 阿里 - 百度 - 字节 ## 思路 这是一道非常适合训练递归的题目。虽然题目不难,但是要想一次写正确,并且代码要足够优雅却不是很容易。 这里我们的思路是定一个递归的 helper 函数,用来帮助我们完成递归操作。 递归函数的功能是将它的左右子树相加,注意这里不包括这个节点本身,否则会多加, 我们其实关注的就是叶子节点的值,然后通过层层回溯到 root,返回即可。 整个过程如图所示: ![129.sum-root-to-leaf-numbers-1](https://tva1.sinaimg.cn/large/007S8ZIlly1ghlu66bb27j30k10a6dgx.jpg) 那么数字具体的计算逻辑,如图所示,相信大家通过这个不难发现规律: ![129.sum-root-to-leaf-numbers-2](https://tva1.sinaimg.cn/large/007S8ZIlly1ghlu67b2mkj30mo0agmys.jpg) ## 关键点解析 - 递归分析 ## 代码 - 语言支持:JS,C++,Python, Go, PHP JS Code: ```js /* * @lc app=leetcode id=129 lang=javascript * * [129] Sum Root to Leaf Numbers */ function helper(node, cur) { if (node === null) return 0; const next = node.val + cur * 10; if (node.left === null && node.right === null) return next; const l = helper(node.left, next); const r = helper(node.right, next); return l + r; } /** * Definition for a binary tree node. * function TreeNode(val) { * this.val = val; * this.left = this.right = null; * } */ /** * @param {TreeNode} root * @return {number} */ var sumNumbers = function (root) { // tag: `tree` `dfs` `math` return helper(root, 0); }; ``` C++ Code: ```C++ /** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode(int x) : val(x), left(NULL), right(NULL) {} * }; */ class Solution { public: int sumNumbers(TreeNode* root) { return helper(root, 0); } private: int helper(const TreeNode* root, int val) { if (root == nullptr) return 0; auto ret = root->val + val * 10; if (root->left == nullptr && root->right == nullptr) return ret; auto l = helper(root->left, ret); auto r = helper(root->right, ret); return l + r; } }; ``` Python Code: ```python # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def sumNumbers(self, root: TreeNode) -> int: def helper(node, cur_val): if not node: return 0 next_val = cur_val * 10 + node.val if not (node.left or node.right): return next_val left_val = helper(node.left, next_val) right_val = helper(node.right, next_val) return left_val + right_val return helper(root, 0) ``` Go Code: ```go /** * Definition for a binary tree node. * type TreeNode struct { * Val int * Left *TreeNode * Right *TreeNode * } */ func sumNumbers(root *TreeNode) int { return helper(root, 0) } func helper(root *TreeNode, cur int) int { if root == nil { return 0 // 当前非叶子节点, 不计算 } next := cur*10 + root.Val if root.Left == nil && root.Right == nil { return next // 当前为叶子节点, 计算 } l := helper(root.Left, next) r := helper(root.Right, next) return l + r } ``` PHP Code: ```php /** * Definition for a binary tree node. * class TreeNode { * public $val = null; * public $left = null; * public $right = null; * function __construct($value) { $this->val = $value; } * } */ class Solution { /** * @param TreeNode $root * @return Integer */ function sumNumbers($root) { return (new Solution())->helper($root, 0); } /** * @param TreeNode $root * @param int $cur * @return int */ function helper($root, $cur) { if (!$root) return 0; // 当前不是叶子节点 $next = $cur * 10 + $root->val; if (!$root->left && !$root->right) return $next; // 当前为叶子节点, 返回叶子节点的值 $l = (new Solution())->helper($root->left, $next); $r = (new Solution())->helper($root->right, $next); return $l + $r; } } ``` **复杂度分析** - 时间复杂度:$O(N)$ - 空间复杂度:$O(N)$ ## 拓展 通常来说,可以利用队列、栈等数据结构将递归算法转为递推算法。 ### 描述 使用两个队列: 1. 当前和队列:保存上一层每个结点的当前和(比如 49 和 40) 2. 结点队列:保存当前层所有的非空结点 每次循环按层处理结点队列。处理步骤: 1. 从结点队列取出一个结点 2. 从当前和队列将上一层对应的当前和取出来 3. 若左子树非空,则将该值乘以 10 加上左子树的值,并添加到当前和队列中 4. 若右子树非空,则将该值乘以 10 加上右子树的值,并添加到当前和队列中 5. 若左右子树均为空时,将该节点的当前和加到返回值中 ## 实现 - 语言支持:C++,Python C++ Code: ```C++ class Solution { public: int sumNumbers(TreeNode* root) { if (root == nullptr) return 0; auto ret = 0; auto runningSum = vector{root->val}; auto queue = vector{root}; while (!queue.empty()) { auto sz = queue.size(); for (auto i = 0; i < sz; ++i) { auto n = queue.front(); queue.erase(queue.begin()); auto tmp = runningSum.front(); runningSum.erase(runningSum.begin()); if (n->left != nullptr) { runningSum.push_back(tmp * 10 + n->left->val); queue.push_back(n->left); } if (n->right != nullptr) { runningSum.push_back(tmp * 10 + n->right->val); queue.push_back(n->right); } if (n->left == nullptr && n->right == nullptr) { ret += tmp; } } } return ret; } }; ``` Python Code: ```python class Solution: def sumNumbers(self, root: TreeNode) -> int: if not root: return 0 result = 0 node_queue, sum_queue = [root], [root.val] while node_queue: for i in node_queue: cur_node = node_queue.pop(0) cur_val = sum_queue.pop(0) if cur_node.left: node_queue.append(cur_node.left) sum_queue.append(cur_val * 10 + cur_node.left.val) if cur_node.right: node_queue.append(cur_node.right) sum_queue.append(cur_val * 10 + cur_node.right.val) if not (cur_node.left or cur_node.right): result += cur_val return result ``` ## 相关题目 - [sum-of-root-to-leaf-binary-numbers](https://leetcode.com/problems/sum-of-root-to-leaf-binary-numbers/) > 这道题和本题太像了,跟一道题没啥区别 大家对此有何看法,欢迎给我留言,我有时间都会一一查看回答。更多算法套路可以访问我的 LeetCode 题解仓库:https://github.com/azl397985856/leetcode 。 目前已经 37K star 啦。 大家也可以关注我的公众号《力扣加加》带你啃下算法这块硬骨头。 ![](https://tva1.sinaimg.cn/large/007S8ZIlly1gfcuzagjalj30p00dwabs.jpg)