LeetCode-Go 题解:107. Binary Tree Level Order Traversal II 自底向上层序遍历

发布时间:2026/9/10 6:46:38

LeetCode-Go 题解:107. Binary Tree Level Order Traversal II 自底向上层序遍历 LeetCode-Go 题解107. Binary Tree Level Order Traversal II 自底向上层序遍历【免费下载链接】LeetCode-Go✅ Solutions to LeetCode by Go, 100% test coverage, runtime beats 100% | LeetCode 题解项目地址: https://gitcode.com/GitHub_Trending/le/LeetCode-Go导读本文深入讲解 LeetCode 第 107 题「二叉树的层序遍历 II」给定一棵二叉树按「自底向上」的顺序返回各层节点值。文章以本仓库leetcode/0107.Binary-Tree-Level-Order-Traversal-II目录下的完整 Go 实现为主线从 BFS 队列层序遍历的底层机制、curNum/nextLevelNum双计数器的工作原理到自底向上的结果翻转再到配套测试用例与structures树工具函数的使用带你彻底掌握这道经典二叉树题目的工程化解法并能在仓库中直接运行验证。题目理解与示例分析题目描述给定一棵二叉树返回其节点值的自底向上的层序遍历bottom-up level order traversal。要求从叶子层到根节点、每一层内从左到右依次收集节点值。以题目给出的二叉树[3, 9, 20, null, null, 15, 7]为例其树形结构如下3 / \ 9 20 / \ 15 7自顶向下的层序遍历结果是[ [3], [9, 20], [15, 7] ]而本题要求从下到上输出因此最终结果为[ [15, 7], [9, 20], [3] ]注意两点关键约束一是层与层之间的顺序完全反转但每一层内部的左右顺序保持不变如[15, 7]而非[7, 15]二是空树的合法输出是空切片[]单节点树输出[[1]]这两个边界在测试用例中都有覆盖。与 102 题的关系自底向上层序遍历可以看作是 102 题「Binary Tree Level Order Traversal」的变体先按常规方式得到自顶向下的层序结果再对整组结果做一次整体反转即可。仓库中本题的实现正是采用了这一先正向、后翻转的简洁策略。解题思路单队列 BFS 结果反转为什么选择队列层序遍历天然适合 BFS广度优先搜索使用一个先进先出的队列从根节点开始每访问一个节点就把它的左右孩子依次入队即可保证逐层、层内从左到右的访问顺序。原文档指出用一个队列即可实现仓库源码也正是如此且没有引入任何额外的数据结构辅助分层而是用两个计数器完成层的切分。整体实现结构本题实现由两个函数协作完成源码见 107. Binary Tree Level Order Traversal II.golevelOrder(root *TreeNode) [][]int完成自顶向下的 BFS 层序遍历返回按层分组的节点值levelOrderBottom(root *TreeNode) [][]int调用levelOrder拿到正向结果后从尾部到头部逐层追加到新切片得到自底向上结果。反转部分的实现细节func levelOrderBottom(root *TreeNode) [][]int { tmp : levelOrder(root) res : [][]int{} for i : len(tmp) - 1; i 0; i-- { res append(res, tmp[i]) } return res }这里采用新建结果切片、倒序追加的方式而不是原地交换每一层tmp[i]是独立的[]int切片倒序追加不会破坏各层内部顺序对于空树levelOrder返回[][]int{}循环不会执行函数直接返回空切片与预期一致。源码级原理剖析BFS 双计数器分层levelOrder是整个算法的核心它只用一个队列和两个计数器就完成了完整的分层func levelOrder(root *TreeNode) [][]int { if root nil { return [][]int{} } queue : []*TreeNode{} queue append(queue, root) curNum, nextLevelNum, res, tmp : 1, 0, [][]int{}, []int{} for len(queue) ! 0 { if curNum 0 { node : queue[0] if node.Left ! nil { queue append(queue, node.Left) nextLevelNum } if node.Right ! nil { queue append(queue, node.Right) nextLevelNum } curNum-- tmp append(tmp, node.Val) queue queue[1:] } if curNum 0 { res append(res, tmp) curNum nextLevelNum nextLevelNum 0 tmp []int{} } } return res }三个变量的职责变量初始值职责queue[root]保存待访问的节点同时承载下一层节点的暂存curNum1当前层剩余待出队节点数用于界定当前层的边界nextLevelNum0下一层累计入队的节点数当前层耗尽时接替curNumtmp[]int{}暂存当前层已收集的节点值逐层推进的完整流程根节点入队curNum 1从队首取出一个节点queue queue[1:]完成出队将其非空左右孩子入队并让nextLevelNum同时把节点值追加进tmpcurNum--当curNum 0时说明当前层已全部处理完把tmp追加进res并将curNum nextLevelNum、nextLevelNum 0、tmp重置为空切片进入下一层当队列为空时所有层均已处理完毕返回res。以示例树为例第一层只有根节点 3出队时 9、20 入队nextLevelNum 2curNum归零后触发换层第二层处理 9、20入队 15、7第三层处理 15、7 后队列为空BFS 结束。整个过程不需要在队列中插入任何层分隔标记仅靠数值计数即可精确切分层次这是该实现最值得学习的点。复杂度分析时间复杂度O(n)每个节点恰好入队、出队各一次附加一次结果整体反转仍为线性空间复杂度O(n)队列最多同时容纳一层的节点最坏情况为满二叉树最后一层的 n/2 个节点加上结果切片res与每层暂存tmp的开销总体为 O(n)。树节点类型与测试数据构造TreeNode 类型定义本题源码开头通过类型别名复用了仓库公共结构体// TreeNode define type TreeNode structures.TreeNode该类型定义在 structures/TreeNode.go结构如下type TreeNode struct { Val int Left *TreeNode Right *TreeNode }仓库将二叉树、链表等通用数据结构抽离到独立的structures包所有 LeetCode 题解统一复用保证了类型一致并避免了每个题目重复定义。用 Ints2TreeNode 构造测试树测试代码通过structures.Ints2TreeNode把 LeetCode 风格的层序数组转换成*TreeNode见 107. Binary Tree Level Order Traversal II_test.gopara107{[]int{3, 9, 20, structures.NULL, structures.NULL, 15, 7}}, ans107{[][]int{{15, 7}, {9, 20}, {3}}},其中structures.NULL定义见 structures/TreeNode.go是一个哨兵值// NULL 方便添加测试数据 var NULL -1 63Ints2TreeNode的转换逻辑structures/TreeNode.go同样基于队列以数组首元素建根逐层为每个节点挂载左右孩子遇到NULL则跳过该子节点。注意它并不支持任意层深的稀疏树仅适用于按层补齐的标准 LeetCode 输入格式这也是在构造复杂测试数据时需要留意的限制。测试用例与运行验证用例设计仓库的测试文件使用参数 期望答案的结构化写法覆盖了三类典型场景输入层序数组期望输出覆盖场景[]空树[]空树边界[1][[1]]单节点树[3, 9, 20, NULL, NULL, 15, 7][[15, 7], [9, 20], [3]]完整的多层二叉树题目示例测试主流程Test_Problem107遍历所有用例将层序数组经Ints2TreeNode建树后调用levelOrderBottom并打印输入与输出用于人工核对。本地运行方式在仓库根目录执行以下命令即可运行本题测试go test -v ./leetcode/0107.Binary-Tree-Level-Order-Traversal-II/ -run Test_Problem107预期会输出形如以下的内容测试通过且无失败断言------------------------Leetcode Problem 107------------------------ 【input】:[] 【output】:[] 【input】:[1] 【output】:[[1]] 【input】:[3 9 20 -9223372036854775808 -9223372036854775808 15 7] 【output】:[[15 7] [9 20] [3]]-9223372036854775808正是structures.NULL-1 63的实际取值说明哨兵值在测试输出中以极值形式呈现不影响断言正确性。该测试属于仓库「100% test coverage」工程实践的一部分仓库根目录的 gotest.sh 与 coverage.txt 记录了全量覆盖率运行方式与结果。小结本题通过队列 BFS 双计数器分层 结果整体反转三步即可优雅解决curNum与nextLevelNum的组合避免了在队列中混入分隔符或记录每层节点数数组是层序遍历中值得反复揣摩的经典写法而把自底向上的需求转化为一次线性反转则体现了先解决正向问题、再变换输出的通用解题思路。仓库中本题的实现与测试实现、测试可直接作为模板迁移到 102 题正向层序及各类锯齿形层序变体题中。【免费下载链接】LeetCode-Go✅ Solutions to LeetCode by Go, 100% test coverage, runtime beats 100% | LeetCode 题解项目地址: https://gitcode.com/GitHub_Trending/le/LeetCode-Go创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/9/10 6:46:38

CANN/ge AIPP销毁接口

aclmdlDestroyAIPP 【免费下载链接】ge GE(Graph Engine)是面向昇腾的图编译器和执行器,提供了计算图优化、多流并行、内存复用和模型下沉等技术手段,加速模型执行效率,减少模型内存占用。 GE 提供对 PyTorch、TensorF…

2026/9/10 7:41:43

Java继承多态接口抽象类,牛客刷题核心考点详解

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/10 7:41:43

RK3588边缘AI视觉算法帧率优化实战:从12fps到45fps的经验

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/10 7:41:43

养宠家庭Model Y换TPE高边脚垫实测:从选型数据到装车避坑

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/10 7:36:43

Go语言实现循环赛算法:固定轮转法详解

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/9 13:11:35

超人会飞不算本事:系统稳定依赖清晰规则与边界设计

开头先不绕弯子。“#斯坦李吐槽dc 所以超人是无缘无故会飞的嘛哈哈哈哈哈哈哈锤哥真是技术人才啊!#雷神 #复联”这类调侃式短标题,第一波冲击力在于它把两个宇宙的角色塞进同一个吐槽箱里,但细想一下就能发现,它真正碰到的根本不是…

2026/9/8 7:15:15

超人VS蜘蛛侠:拆解超级IP的影响力与传播方法论

把“蜘蛛侠 vs 超人”放在 CSDN 上聊,可能很多人第一反应是走错片场了。但如果把这两个角色看成“两个持续运营了 80 多年的文化产品”,你会发现,这场比较本质上是两个不同 IP 策略的长期结果对比:超人赢在定义了整个超级英雄题材…

2026/9/9 16:31:09

基于CNN的调制信号识别:MATLAB实现时频图分类实战

简介:本资源是一套面向通信工程与信号处理方向学习者、研究者的深度学习实践方案,聚焦调制信号自动检测与识别这一典型无线通信任务,解决传统方法依赖人工特征、低信噪比下性能下降等痛点。压缩包共12个文件(10.73MB)&…

2026/9/10 0:00:55

目录对比去重实战:用哈希算法精准清理重复文件

我电脑里现在还有一块换了三次机的“数据墓地”硬盘,里面存着2016年以前所有旧笔记本的完整备份。平时不觉得有什么,直到前阵子想把它整理归档,发现同一个安装包、同一批照片、同一份论文草稿,在几个不同的备份目录里反复出现。更…

2026/9/10 0:00:55

Leaflet离线地图完整Demo合集:内网部署与坐标纠偏实战

简介:这是一份面向Web GIS开发者的LeafLet离线地图示例合集,帮助开发者快速掌握离线地图从搭建到交互的完整流程。压缩包共723个文件,大小14.06MB,以319个js脚本、175个html页面和29个css样式文件为主体,配合png/svg图…

2026/9/10 0:00:55

MATLAB读取Rinex 3.02观测文件:多系统GNSS数据解析实战

简介:基于MATLAB开发的Rinex3.02版观测文件(o文件)读取代码包,面向卫星定位导航方向的学习者与研究人员,用于解决新版观测文件的数据解析、历元提取与时间转换问题。压缩包共4个文件,包含两个m脚本、一个19…

2026/9/7 16:23:03

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/7 22:46:00

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/9 10:21:54

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码