129. 求根到叶子节点数字之和(Sum Root to Leaf Numbers):递归 DFS 与双队列递推双解法精讲
129. 求根到叶子节点数字之和Sum Root to Leaf Numbers递归 DFS 与双队列递推双解法精讲【免费下载链接】leetcodeLeetCode Solutions: A Record of My Problem Solving Journey.( leetcode题解记录自己的leetcode解题之路。)项目地址: https://gitcode.com/gh_mirrors/le/leetcode导读本文以 LeetCode 129 题《求根到叶子节点数字之和》为核心系统讲解如何将从根到叶子节点的路径编码为十进制数字并求和。你会掌握一条极其优雅的递归范式helper 携带当前累计值自顶向下传递以及用两个队列把递归改写成层序递推的完整实现覆盖 JS、C、Python、Go、PHP 五种语言。该题收录于 leetcode 仓库的 problems/129.sum-root-to-leaf-numbers.md并在 SUMMARY.md 中被归类为中等难度题。题目描述给定一个二叉树它的每个结点都存放一个 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.前置知识递归DFS深度优先遍历二叉树的基本遍历本题在仓库的 thinkings/DFS.md 中属于深度优先遍历专题的典型应用DFS 概念源自图论但在搜索题中一般指通过递归函数实现的暴力枚举而树的题目几乎都可以使用 DFS 解决且基于递归的实现更简洁、更不易出错。公司阿里百度字节思路携带当前累计值的自顶向下递归这是一道非常适合训练递归的题目。虽然题目不难但是要想一次写正确并且代码要足够优雅却不是很容易。核心思路是定一个递归的 helper 函数用来帮助我们完成递归操作。递归函数的功能是将它的左右子树相加注意这里不包括这个节点本身否则会多加我们其实关注的就是叶子节点的值然后通过层层回溯到 root返回即可。递归调用的关键设计如下helper 接收两个参数当前节点 node 与从根到父节点的累计数字 cur遇到空节点返回 0空节点不产生路径属于当前不是叶子节点、不计算的兜底分支用公式next cur * 10 node.val将当前节点拼接进路径数字若当前节点是叶子左右孩子均为空直接返回 next即这条根到叶子的路径完整了否则递归计算左、右子树并把两棵子树的所有叶子路径数字之和相加返回。数字拼接的计算逻辑如下图所示——每一步都是父路径数字 × 10 当前节点数字例如路径 4-9-5根节点 4到 9 得到 4×10949再到 5 得到 49×105495关键点解析递归分析明确空节点返回 0与叶子节点返回累计值两个终止条件的分工状态传递把 cur父路径累计值作为递归参数自顶向下传递避免使用全局变量回溯汇总左右子树的结果相加逐层返回给上层最终在根节点得到全部叶子路径数字之和。仓库在 assets/drawio/129.sum-root-to-leaf-numbers.drawio 中提供了本题的 draw.io 流程图可配合本文的递归调用关系对照理解。代码语言支持JSCPython, Go, PHPJS Code/* * lc appleetcode id129 langjavascript * * [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/** * 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:# 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/** * 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/** * 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)$最坏情况下树退化为链递归调用栈深度为 N平均情况下为树高 $O(\log N)$拓展用双队列将递归改写为层序递推通常来说可以利用队列、栈等数据结构将递归算法转为递推算法。递归版本依赖系统调用栈隐式保存每条路径的累计值而递推版本则用两个队列显式保存。描述使用两个队列当前和队列保存上一层每个结点的当前和比如 49 和 40结点队列保存当前层所有的非空结点每次循环按层处理结点队列。处理步骤从结点队列取出一个结点从当前和队列将上一层对应的当前和取出来若左子树非空则将该值乘以 10 加上左子树的值并添加到当前和队列中若右子树非空则将该值乘以 10 加上右子树的值并添加到当前和队列中若左右子树均为空时将该节点的当前和加到返回值中实现语言支持CPythonC Codeclass Solution { public: int sumNumbers(TreeNode* root) { if (root nullptr) return 0; auto ret 0; auto runningSum vectorint{root-val}; auto queue vectorconst TreeNode*{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 Codeclass 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两种写法一一对应递归里 helper 的 cur 参数就是递推里 sum_queue 队头的元素递归里叶子返回 next就是递推里左右孩子均为空时把 tmp 累加到 result。按层处理时每一层结束意味着上一层的全部路径数字都已展开到下一层或已作为叶子求和因此不会出现重复计数或漏加。小结与相关题目本题是二叉树 DFS 递归的经典入门题掌握helper 携带累计值 两个终止条件 左右子树结果相加这一模式后可无障碍迁移到其他路径求和类题目。相关题目sum-of-root-to-leaf-binary-numbers这道题和本题太像了跟一道题没啥区别区别仅在节点值是 0/1 二进制拼接公式从十进制 ×10 换成二进制 ×2。进一步巩固可阅读仓库 thinkings/DFS.md 的深度优先遍历专题与 thinkings/tree.md 的树专题该类中等二叉树题目在 collections/medium.md 中也有收录适合集中刷题对比。【免费下载链接】leetcodeLeetCode Solutions: A Record of My Problem Solving Journey.( leetcode题解记录自己的leetcode解题之路。)项目地址: https://gitcode.com/gh_mirrors/le/leetcode创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

性价比高的婚庆套房酒店推荐:周边商圈配套齐全,出行便捷

性价比高的婚庆套房酒店推荐:周边商圈配套齐全,出行便捷

什么是符合大众需求的高性价比酒店,带你快速建立行业认知对于有住宿需求的消费者来说,不管是商务出差、休闲出行,还是举办小型主题活动比如婚庆聚会、朋友派对,选择合适的酒店直接影响整个行程的体验感。很多人对酒店的认知还停留…

2026/9/19 11:50:19 阅读更多 →
无人机飞控原理:从IMU融合到串级PID的实时闭环控制

无人机飞控原理:从IMU融合到串级PID的实时闭环控制

简介:本资源是一份面向无人机系统工程师、飞控算法初学者及高校相关专业学生的专业技术课件,聚焦飞控系统核心原理与控制律设计,解决对比例式、积分式及均衡式反馈自动驾驶仪理解不深、难以区分动态响应与稳态特性的实际学习痛点。课件以PPTX…

2026/9/19 11:49:19 阅读更多 →
ARINC 705-5-1985:AHRS与MSU接口设计的工程契约

ARINC 705-5-1985:AHRS与MSU接口设计的工程契约

简介:本资源为航空电子领域权威标准文档ARINC 705-5(1985年发布),全称《Attitude and Heading Reference System》,面向航电工程师、惯性导航系统研发人员及航空院校师生,用于指导姿态与航向参考系统&#…

2026/9/19 11:49:19 阅读更多 →

最新新闻

ESP-IoT-Solution 按钮组件实战指南:GPIO / ADC / 矩阵按键的创建、事件回调与低功耗设计

ESP-IoT-Solution 按钮组件实战指南:GPIO / ADC / 矩阵按键的创建、事件回调与低功耗设计

ESP-IoT-Solution 按钮组件实战指南:GPIO / ADC / 矩阵按键的创建、事件回调与低功耗设计 【免费下载链接】esp-iot-solution Espressif IoT Library. IoT Device Drivers, Documentations and Solutions. 项目地址: https://gitcode.com/GitHub_Trending/es/esp-…

2026/9/19 12:58:47 阅读更多 →
Edge浏览器扩展vCaptions:让B站视频实时转文字,高效提取字幕与笔记

Edge浏览器扩展vCaptions:让B站视频实时转文字,高效提取字幕与笔记

1. 一个Edge扩展,把B站视频变成可搜索的文字我平时在B站上看得最多的不是娱乐视频,而是一堆编程课、产品分享和演讲录像。看完想复盘的时候,最折磨人的不是内容难,而是“有一句话很重要,但我忘了是几分钟说的”。拖动进…

2026/9/19 12:58:46 阅读更多 →
create-t3-app 中的 Prisma 集成指南:Schema 设计、Prisma Client 与数据库填充实战

create-t3-app 中的 Prisma 集成指南:Schema 设计、Prisma Client 与数据库填充实战

create-t3-app 中的 Prisma 集成指南:Schema 设计、Prisma Client 与数据库填充实战 【免费下载链接】create-t3-app The best way to start a full-stack, typesafe Next.js app 项目地址: https://gitcode.com/gh_mirrors/cr/create-t3-app Prisma 是 cre…

2026/9/19 12:58:46 阅读更多 →
如何快速上手location-to-phone-number?从手机号定位到地图导航的零基础入门教程

如何快速上手location-to-phone-number?从手机号定位到地图导航的零基础入门教程

如何快速上手location-to-phone-number?从手机号定位到地图导航的零基础入门教程 【免费下载链接】location-to-phone-number This a project to search a location of a specified phone number, and locate the map to the phone number location. 项目地址: ht…

2026/9/19 12:58:46 阅读更多 →
AI内容安全审核系统搭建实战指南

AI内容安全审核系统搭建实战指南

我不能按照该标题生成内容。该标题涉及不适宜、违反社会公序良俗及内容安全规范的表述,其中“AI 色情”属于明确禁止传播的违法不良信息范畴。根据中国法律法规及网络信息内容生态治理要求,任何形式的色情、低俗、违法不良信息(包括借助AI技术…

2026/9/19 12:58:46 阅读更多 →
智慧林业生态大数据平台:从数据入湖到碳汇计算的全链路实践

智慧林业生态大数据平台:从数据入湖到碳汇计算的全链路实践

简介:一份智慧林业生态大数据平台建设方案演示文稿,共27页,面向林业信息化项目规划、方案编写与汇报演示人群。内容系统梳理了智慧林业的兴起内涵、国家政策与建设意义,涵盖平台总体架构、数据共享平台、三大基础数据库、多元数据…

2026/9/19 12:57:46 阅读更多 →

日新闻

BP神经网络时序预测:滑窗长度与多窗口平均策略

BP神经网络时序预测:滑窗长度与多窗口平均策略

简介:面向机器学习、深度学习与数据建模学习者的一份完整研究文献,聚焦BP神经网络在农业产量预测中的应用。文档以1980—2018年全国棉花产量为样本,系统讲解数据归一化处理、激活函数原理、多层神经网络结构搭建及训练流程,展示敏…

2026/9/19 0:00:30 阅读更多 →
Transformer训练实时监控实战:基于MindSpore的损失曲线可视化方案

Transformer训练实时监控实战:基于MindSpore的损失曲线可视化方案

上个月调一个Deformable DETR模型,在单卡上要跑将近两天。第二天早上我下意识打开终端翻日志,发现loss从凌晨两点就开始往上爬,一路从0.8涨到1.35,整整六个小时没人发现。那六个小时的训练不仅白跑,还霸占着卡——等于…

2026/9/19 0:00:30 阅读更多 →
OpenCloud 中的 Go 类型安全转换库 spf13/cast:从零值回退到泛型 API 的完整实战指南

OpenCloud 中的 Go 类型安全转换库 spf13/cast:从零值回退到泛型 API 的完整实战指南

OpenCloud 中的 Go 类型安全转换库 spf13/cast:从零值回退到泛型 API 的完整实战指南 【免费下载链接】opencloud 🌤️ OpenCloud is the open source platform for file management, sharing and collaboration. Simple and sovereign. 项目地址: htt…

2026/9/19 0:00:30 阅读更多 →

周新闻

AI SDK Harness 依赖更新指南:掌握 harness 包 SDK 依赖的升级、桥接同步与一致性校验

AI SDK Harness 依赖更新指南:掌握 harness 包 SDK 依赖的升级、桥接同步与一致性校验

AI SDK Harness 依赖更新指南:掌握 harness 包 SDK 依赖的升级、桥接同步与一致性校验 【免费下载链接】ai The AI Toolkit for TypeScript. From the creators of Next.js, the AI SDK is a free open-source library for building AI-powered applications and ag…

2026/9/19 3:59:36 阅读更多 →
Refine v5 Ant Design NumberField 组件实战:基于 Intl 的本地化数字格式化

Refine v5 Ant Design NumberField 组件实战:基于 Intl 的本地化数字格式化

Refine v5 Ant Design NumberField 组件实战:基于 Intl 的本地化数字格式化 【免费下载链接】refine A React Framework for building internal tools, admin panels, dashboards & B2B apps with unmatched flexibility. 项目地址: https://gitcode.com/GitH…

2026/9/19 3:53:08 阅读更多 →
Flutter应用改名全指南:从Android到iOS的配置与工具实践

Flutter应用改名全指南:从Android到iOS的配置与工具实践

刚接一个外包项目时,甲方要求把工程里临时用的应用名改成正式产品名。我本来觉得“改名”这种小事,打开配置文件改一行不就完了?结果真动手才发现,Flutter项目里“应用名称”根本不是一处配置,而是一整套散落在 Androi…

2026/9/19 4:02:43 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/16 22:31:27 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/15 21:39:18 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/16 22:32:59 阅读更多 →