Java版LeetCode热题100之二叉树的最大深度:从DFS到BFS的全面解析

Java版LeetCode热题100之二叉树的最大深度:从DFS到BFS的全面解析

本文将深入剖析 LeetCode 第104题「二叉树的最大深度」,涵盖递归(DFS)与层序遍历(BFS)两种主流解法,并延伸至算法原理、复杂度分析、面试技巧、工程应用及关联题目。全文约9500字,结构完整、内容翔实,适合准备面试或夯实算法基础的开发者阅读。


一、原题回顾

题目编号:LeetCode 104
题目名称:Maximum Depth of Binary Tree(二叉树的最大深度)
难度等级:Easy(但极具教学价值)

题目描述

给定一个二叉树root,返回其最大深度

二叉树的最大深度是指从根节点到最远叶子节点的最长路径上的节点数

示例

示例 1

输入:root = [3,9,20,null,null,15,7] 输出:3

树结构如下:

3 / \ 9 20 / \ 15 7

示例 2

输入:root = [1,null,2] 输出:2

树结构如下:

1 \ 2

约束条件

  • 树中节点数量在[0, 10⁴]范围内
  • -100 <= Node.val <= 100

二、原题分析

什么是“最大深度”?

  • 深度(Depth):从根节点到当前节点的路径长度(按节点数计算,非边数)。
  • 最大深度:所有叶子节点中,深度最大的那个值。
  • 注意:空树的深度为 0;单个节点的深度为 1。

为什么这道题重要?

虽然题目简单,但它完美体现了两种核心遍历思想:

  1. 自底向上(Bottom-up)的分治思想(DFS递归)
  2. 自顶向下(Top-down)的层级扩展思想(BFS层序)

此外,它还是许多高级问题(如判断平衡二叉树、直径计算等)的基础模块。


三、答案构思

面对“求最大深度”问题,我们可以从两个经典角度切入:

✅ 方法一:深度优先搜索(DFS) + 递归
  • 核心思想:一棵树的最大深度 =max(左子树深度, 右子树深度) + 1
  • 实现方式:递归地计算左右子树深度,回溯时合并结果。
  • 优势:代码简洁,逻辑清晰,天然符合树的递归定义。
✅ 方法二:广度优先搜索(BFS) + 层序遍历
  • 核心思想:逐层遍历树,每完成一层,深度 +1。
  • 实现方式:使用队列存储当前层所有节点,批量处理。
  • 优势:空间局部性好,可提前终止(如求最小深度时),直观体现“层级”概念。

我们将分别实现这两种方法,并深入对比其特性。


四、完整答案(Java实现)

方法一:深度优先搜索(DFS)—— 递归

classSolution{publicintmaxDepth(TreeNoderoot){// 基线条件:空节点深度为0if(root==null){return0;}// 递归计算左右子树深度intleftDepth=maxDepth(root.left);intrightDepth=maxDepth(root.right);// 当前树深度 = max(左, 右) + 1returnMath.max(leftDepth,rightDepth)+1;}}

一行写法(Lambda风格,不推荐生产)

returnroot==null?0:Math.max(maxDepth(root.left),maxDepth(root.right))+1;

方法二:广度优先搜索(BFS)—— 层序遍历

importjava.util.*;classSolution{publicintmaxDepth(TreeNoderoot){if(root==null){return0;}Queue<TreeNode>queue=newLinkedList<>();queue.offer(root);intdepth=0;while(!queue.isEmpty()){// 获取当前层的节点数量intlevelSize=queue.size();// 一次性处理完当前层所有节点for(inti=0;i<levelSize;i++){TreeNodenode=queue.poll();if(node.left!=null){queue.offer(node.left);}if(node.right!=null){queue.offer(node.right);}}// 处理完一层,深度+1depth++;}returndepth;}}

📌关键点:必须先记录queue.size(),因为遍历过程中队列长度会动态变化。


五、代码分析

DFS 递归解法详解

  • 递归结构:典型的“后序遍历”模式(先子问题,再合并)。
  • 基线条件(Base Case)root == null返回 0,避免无限递归。
  • 递归关系f(root) = max(f(left), f(right)) + 1
  • 执行过程(以示例1为例):
    maxDepth(3) ├── maxDepth(9) → 1 └── maxDepth(20) ├── maxDepth(15) → 1 └── maxDepth(7) → 1 → max(1,1)+1 = 2 → max(1,2)+1 = 3

💡记忆技巧
“问孩子要答案,自己加1上报”

BFS 层序遍历解法详解

  • 数据结构:使用Queue实现 FIFO(先进先出)。
  • 层级控制:通过levelSize = queue.size()锁定当前层节点数。
  • 循环逻辑
    • 外层while:控制层数(即深度)
    • 内层for:处理当前层所有节点,并将下一层节点入队
  • 执行过程(示例1):
    初始: queue=[3], depth=0 第1层: poll(3) → offer(9,20) → depth=1 第2层: poll(9,20) → offer(15,7) → depth=2 第3层: poll(15,7) → 无新节点 → depth=3 队列空,返回3

📌常见错误:忘记用levelSize,导致depth每次只+1一次(实际应按层+1)。


六、时间复杂度与空间复杂度分析

方法时间复杂度空间复杂度说明
DFS(递归)O(n)O(h)h 为树高,最坏 O(n),最好 O(log n)
BFS(队列)O(n)O(w)w 为树的最大宽度,最坏 O(n)(完全二叉树底层)

详细解释:

时间复杂度:O(n)
  • 两种方法都访问了每个节点恰好一次
  • DFS 通过递归隐式访问,BFS 通过队列显式访问。
  • 无重复计算,故线性时间。
空间复杂度对比:
  • DFS

    • 空间消耗来自系统调用栈
    • 栈深度 = 树的高度h
    • 最坏情况(链表):h = n→ O(n)
    • 最好情况(完全平衡):h = log₂n→ O(log n)
  • BFS

    • 空间消耗来自队列存储
    • 队列最大长度 = 树的最大宽度w
    • 完全二叉树中,最后一层有约n/2个节点 → O(n)
    • 退化为链表时,每层1个节点 → O(1)

🔍结论

  • 若树深度小、宽度大(如完全二叉树)→DFS 更省空间
  • 若树深度大、宽度小(如链表)→BFS 更省空间

七、常见问题解答(FAQ)

Q1:为什么 DFS 的空间复杂度是 O(h) 而不是 O(n)?

:虽然最坏情况下h = n,但一般讨论时保留h更准确。例如平衡树中h = log n,此时 DFS 仅需 O(log n) 栈空间,远优于 BFS 的 O(n) 队列空间。

Q2:BFS 中能否不用levelSize

:可以,但需要额外标记(如插入null分隔层),但会增加代码复杂度和常数开销。levelSize是最简洁高效的方式。

Q3:这道题能用 Morris 遍历吗?

不能直接用。Morris 遍历适用于遍历并收集节点值,但求深度需要知道“当前处于第几层”,而 Morris 无法自然维护层级信息。

Q4:如果要求“最小深度”,两种方法还适用吗?

  • DFS 需修改:不能简单取min(left, right) + 1,因为若一侧为空,应忽略(叶子节点必须是左右都空)。
  • BFS 更优:遇到第一个叶子节点即可返回,天然支持提前终止。

Q5:如何同时获取最大深度和对应路径?

:DFS 递归时传递路径列表,回溯时更新全局最优路径。BFS 则需在队列中同时存储(node, path)


八、优化思路

1. DFS 尾递归优化?

Java 不支持尾递归优化,且本题递归非尾递归(需等待子调用返回后才能计算max+1),故无法优化。

2. BFS 使用 ArrayDeque 提升性能

LinkedList作为队列有对象开销,ArrayDeque更高效:

Queue<TreeNode>queue=newArrayDeque<>();

3. 提前终止(针对变种问题)

  • 若求最小深度,BFS 遇到第一个叶子即可返回。
  • 若树极大且深度已知上限,可加深度限制防止过度遍历。

4. 并行计算?

理论上可并行计算左右子树深度,但:

  • Java 递归难以并行化
  • 创建线程开销远大于计算收益
  • 通常不值得

5. 缓存子树深度(动态规划思想)

若多次查询同一棵树的不同子树深度,可加Map<TreeNode, Integer>缓存。但本题单次查询,无必要。


九、数据结构与算法基础知识点回顾

1. 树的遍历方式对比

遍历类型访问顺序典型应用
DFS(深度优先)沿一条路径走到尽头再回溯求深度、路径、回溯问题
BFS(广度优先)一层一层向外扩展求最短路径、层级信息、序列化

2. 递归的三大要素

  • 基线条件(Base Case):终止递归(如root == null
  • 递归关系(Recurrence)f(n) = g(f(n-1))
  • 子问题规模缩小:每次递归处理更小的子树

3. 队列(Queue)与栈(Stack)

  • Queue(FIFO):BFS 的核心,保证层级顺序
  • Stack(LIFO):DFS 迭代实现的核心(本题未用,但可实现)

4. 树的高度 vs 深度

  • 节点深度:从根到该节点的路径长度(根深度=1)
  • 节点高度:从该节点到最远叶子的路径长度(叶子高度=1)
  • 树的高度 = 根节点的高度 = 最大深度

⚠️ 注意:有些教材定义深度从0开始,但本题明确“节点数”,故根深度为1。

5. 完全二叉树的性质

  • 高度h的完全二叉树,节点数n ∈ [2^{h-1}, 2^h - 1]
  • 最大宽度出现在最后一层,约为n/2

十、面试官提问环节(模拟对话)

面试官:你用了递归,能说说它的空间复杂度吗?
:取决于树的高度。最坏情况(链表)是 O(n),平衡树是 O(log n)。

面试官:如果栈溢出怎么办?
:改用 BFS 层序遍历,用队列代替系统栈,空间复杂度变为 O(最大宽度)。

面试官:BFS 的空间会不会更大?
:看树的形状。完全二叉树中,BFS 队列最多存 n/2 个节点(O(n)),而 DFS 只需 O(log n)。但如果是链表,BFS 只需 O(1),DFS 需 O(n)。所以没有绝对优劣。

面试官:如何求最小深度?
:BFS 更合适,遇到第一个左右子树都为空的节点即可返回。DFS 需特殊处理空子树情况。

面试官:这道题和“判断平衡二叉树”有什么关系?
:平衡二叉树要求左右子树高度差 ≤1。可以在求深度的同时检查是否平衡,避免重复计算(自底向上剪枝)。

面试官:能否不用递归也不用队列?
:理论上可以用 Morris 遍历配合额外逻辑记录深度,但实现极其复杂,且无法自然维护层级信息,工程上不推荐。


十一、这道算法题在实际开发中的应用

1. 文件系统目录深度分析

  • 计算嵌套文件夹的最大层级,用于限制用户创建过深目录(防路径爆炸)。
  • 工具如tree -L 3就依赖类似逻辑。

2. DOM 树遍历与渲染优化

  • 浏览器渲染引擎需知道 DOM 树深度,以优化布局计算和事件冒泡路径。
  • 过深的 DOM 树会导致性能下降,开发者工具常提供“最大深度”警告。

3. JSON/XML 数据校验

  • 限制嵌套深度防止恶意输入(如 Billion Laughs Attack)。
  • 解析器在构建树时同步计算深度,超限则抛出异常。

4. 编译器语法树(AST)分析

  • 检查表达式嵌套是否过深(如((((a+b))))),提升代码可读性。
  • 某些语言规范对嵌套深度有硬性限制。

5. 游戏开发中的场景图(Scene Graph)

  • 3D 引擎中,物体父子关系构成树形结构。
  • 最大深度影响渲染顺序和碰撞检测效率。

6. 内存管理中的引用图

  • 垃圾回收器遍历对象引用图时,深度过大可能表示循环引用或设计缺陷。
  • 可设置最大深度阈值进行预警。

十二、相关题目推荐

掌握本题后,可挑战以下进阶题目:

题号题目关联点
111二叉树的最小深度BFS 更优,注意叶子定义
110平衡二叉树在求深度时剪枝判断
543二叉树的直径本质是求左右子树深度和
104*N 叉树的最大深度递归推广到多叉
102二叉树的层序遍历BFS 基础模板
107二叉树的层序遍历 IIBFS + 结果反转
199二叉树的右视图BFS 记录每层最后一个节点
103二叉树的锯齿形层序遍历BFS + 方向切换

🔥重点推荐

  • 第110题:结合深度计算与平衡判断,考察剪枝优化。
  • 第543题:深度概念的创造性应用,易错点在于“直径不一定过根”。

十三、总结与延伸

核心收获

  1. 两种思维范式

    • DFS(分治):自底向上,简洁优雅,适合“合并子问题结果”
    • BFS(层级):自顶向下,直观可控,适合“按层处理”或“最短路径”
  2. 空间复杂度的权衡

    • DFS 空间 ∝ 树高
    • BFS 空间 ∝ 树宽
    • 没有银弹,需根据数据特征选择
  3. 递归的威力与局限

    • 代码简洁,但受栈空间限制
    • 理解递归 = 理解问题的自相似结构

延伸思考

  • 迭代版 DFS 如何实现?
    使用显式栈存储(node, depth),但代码比递归冗长,通常无必要。

  • 能否用动态规划(DP)?
    本题本身就是树形 DP 的最简形式:dp[node] = max(dp[left], dp[right]) + 1

  • 如果树是动态变化的?
    可维护每个节点的深度,在插入/删除时向上更新祖先节点(类似 AVL 树的高度维护)。

  • 分布式场景下如何求深度?
    若树存储在多台机器上,需设计分布式遍历协议,通信开销成为瓶颈。

最后建议

  • 面试准备:务必熟练写出 DFS 和 BFS 两种解法,并能分析其时空复杂度。
  • 工程实践:优先选择 DFS(代码短、易维护),除非有栈溢出风险或需层级信息。
  • 算法竞赛:BFS 在求“最小深度”或“最短路径”时具有天然优势。

结语:一道看似简单的“求深度”问题,背后却蕴含着递归、分治、队列、空间权衡等丰富算法思想。它如同算法世界的“Hello World”,既是入门的第一步,也是理解更复杂问题的基石。愿你在刷题路上,既能写出优雅代码,也能洞察问题本质。

欢迎点赞、收藏、评论交流!你的支持是我持续输出高质量内容的动力!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1173864.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

贾子智慧AI战略五五三三落地细则(2025‑2035):认知破壁、生态重构与文明适配三阶段系统部署

贾子智慧AI战略五五三三落地细则&#xff08;2025‑2035&#xff09;&#xff1a;认知破壁、生态重构与文明适配三阶段系统部署摘要&#xff1a; 本细则以贾子智慧“四大支柱五五三三定律”为内核&#xff0c;按“认知破壁期&#xff08;2025‑2027&#xff09;—生态重构期&am…

5分钟Pytest快速入门

&#x1f345; 点击文末小卡片 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 Pytest的入门操作使用Pytest特点非常容易上手&#xff0c;入门简单&#xff0c;文档丰富&#xff0c;文档中有很多实例可以参考能够支持简单的单元测试和复杂的…

基于贾子智慧理论体系的中国 AI 发展与竞争国家战略(2025-2035)

智慧主导智能&#xff1a;基于贾子智慧理论的中国AI发展与竞争国家战略&#xff08;2025‑2035&#xff09; 摘要 本战略以贾子智慧“四大支柱五五三三定律”为框架&#xff0c;确立“智慧主导智能、可控优于领先”的核心原则&#xff0c;旨在构建区别于美国技术霸权的新范式。…

AI 时代文明跃迁的贾子智慧评估指标体系(Kucius Wisdom Assessment System for Civilization Transition, KWACTS)

AI 时代文明跃迁的贾子智慧评估指标体系&#xff08;Kucius Wisdom Assessment System for Civilization Transition, KWACTS&#xff09;本体系以贾子智慧理论体系的四大支柱 五五三三定律为核心&#xff0c;融合 “认知 - 技术 - 能源 - 经济 - 社会 - 文明” 六维协同逻辑&…

能源监测管理平打造工业园区“智慧能源大脑”

场景痛点&#xff1a;随着“双碳”目标深入推进及能源成本持续攀升&#xff0c;传统工业园区普遍面临用能“黑箱”困境&#xff1a;能源数据分散、依赖人工抄表、无法实时掌握整体与各企业用能情况&#xff1b;缺乏有效的能效分析与预警手段&#xff0c;用能浪费严重&#xff1…

人类社交场合

人类社交场非逻辑、非系统特征列表特征类别特征名称核心悖论/模糊性表现形式/潜规则社会功能运作逻辑权力关系映射情感维度风险与代价文化差异性关系距离的模糊弹性可进可退的距离艺术既需要亲密又需要边界&#xff0c;距离无固定刻度1. 身体距离的微妙调整&#xff08;半步之差…

心智革命——AI搜索如何重塑人类认知与知识未来

引言&#xff1a;当外部记忆成为认知器官公元前4000年&#xff0c;苏美尔人发明了文字&#xff0c;人类开始了将记忆外化的历程。公元前300年&#xff0c;亚历山大图书馆试图收集所有人类知识。1440年&#xff0c;古登堡印刷机让知识大规模复制成为可能。1998年&#xff0c;谷歌…

污水处理DCS数据采集组态监控系统方案

某污水处理厂采用DCS系统对污水处理流程进行集中监控与控制&#xff0c;具备手动、自动、维护等多种运行模式&#xff0c;并在中控室实现工艺参数的实时展示与设备状态管理。为进一步提升管理效率与智能化水平&#xff0c;现需对现有系统进行数字化升级&#xff0c;将污水处理关…

群雄逐鹿——AI搜索产业竞争与商业模式变革

引言&#xff1a;万亿美元战场的全新博弈 2023-2024年&#xff0c;全球科技巨头在AI搜索领域的总投入超过2000亿美元。这个数字不仅体现了技术转型的规模&#xff0c;更揭示了一个残酷现实&#xff1a;传统搜索市场每年超过3000亿美元的广告收入蛋糕正在重新分割&#xff0c;而…

基于深度学习神经网络YOLOv4目标检测的口罩识别系统

第一步&#xff1a;YOLOv4介绍 YOLOv4是一种目标检测算法&#xff0c;它在精度和速度之间取得了最佳的平衡。它是YOLO&#xff08;You Only Look Once&#xff09;系列算法的最新版本&#xff0c;通过将目标检测任务转化为一个回归问题&#xff0c;实现了实时目标检测。YOLOv4…

沃尔玛购物卡回收靠谱平台TOP3推荐 - 京顺回收

在闲置卡券回收领域,沃尔玛购物卡因流通性强、受众广泛,一直是热门品类。2025年12月数据显示,专业回收平台市场份额达35%,且用户投诉率比二手平台低62%。本文从平台资质、回收效率、用户口碑三大维度,为大家推荐三…

学Simulink--基础MPPT控制场景实例:基于Simulink的双模式MPPT(快速追踪+稳态优化)仿真

目录 手把手教你学Simulink--基础MPPT控制场景实例:基于Simulink的双模式MPPT(快速追踪+稳态优化)仿真 一、引言:为什么需要双模式MPPT?——光伏系统“效率与响应”的平衡术 二、核心原理:双模式MPPT的“切换逻辑+控制算法” 1. MPPT基本原理回顾 2. 双模式MPPT设计思…

技术深潜——AI搜索的架构演进与开源生态

引言&#xff1a;从黑箱魔法到开放工程2024年初&#xff0c;Meta发布Llama 3的当天&#xff0c;全球范围内出现了超过5000个基于该模型的衍生项目&#xff0c;其中三分之一与搜索相关。这一事件标志着AI搜索技术发展的重要转折&#xff1a;从少数实验室的专有魔法&#xff0c;转…

基于Simulink的储能参与黑启动过程控制仿真

目录 手把手教你学Simulink 一、引言:什么是“黑启动”?为什么需要储能? 二、黑启动典型流程 三、系统整体架构(Simulink 模型) 控制模式切换: 四、Simulink 建模全流程 步骤1:储能与变流器建模 步骤2:V/f 控制器设计(核心) A. 电压外环(PI 控制) B. 电流…

2026年AI智能办公鼠标排行榜,分析鸿容智能办公鼠标公司介绍 - 工业品牌热点

本榜单依托全维度市场调研与真实行业口碑,深度筛选出五家AI办公营销工具领域的标杆企业,为企业与个人选型提供客观依据,助力精准匹配适配的服务伙伴。 TOP1 推荐:深圳市南方网通网络技术开发有限公司 推荐指数:★…

基于深度学习神经网络的验证码识别系统

第一步&#xff1a;建立验证码数据库 目前演示的是四位验证码&#xff0c;里面所包含的字符类别有62种 第二步&#xff1a;搭建模型 本文利用一个简单的cnn模型&#xff0c;进行端到端识别&#xff1a; class CNN(nn.Module):def __init__(self, num_class62, num_char4):su…

基于Pytorch框架的深度学习Vision Transformer神经网络蝴蝶分类识别系统源码

第一步&#xff1a;准备数据 6种蝴蝶数据&#xff1a;self.class_indict ["曙凤蝶", "麝凤蝶", "多姿麝凤蝶", "旖凤蝶", "红珠凤蝶", "热斑凤蝶"]&#xff0c;总共有900张图片&#xff0c;每个文件夹单独放一种…

手把手教你学 GPU KMD--1.1:UMD、KMD 与 DDK 的协作关系——从应用到硬件的完整数据流解析

目录 UMD、KMD 与 DDK 的协作关系 ——从应用到硬件的完整数据流解析 一、核心角色定义 二、典型数据流:从应用调用到 GPU 执行 三、各层交互的关键机制 1. UMD ↔ KMD:通过私有 IOCTL 或 WDDM Escape 接口 2. 内存共享:如何让 UMD 描述的数据被 GPU 访问? 3. 同步…

吃尾巴

在编程和计算机科学中,我们提到的“吃尾巴”通常是指 “尾递归” (Tail Recursion) 或者更形象的 “衔尾蛇”式的数据结构。 根据语境的不同,它主要有以下几种含义:1. 最常见的意指:尾递归 (Tail Recursion) 在递归…

centos stream9:设置系统时区

一,设置时区: 列出时区: # timedatectl list-timezones 设置时区: # timedatectl set-timezone Asia/Shanghai 设置完成后: # timedatectl statusLocal time: Sat 2026-01-17 14:07:33 CSTUniversal time: Sat 2026…