力扣hot100之104:二叉树的最大深度
力扣hot100之104:二叉树的最大深度

LeetCode 104:二叉树的最大深度(Maximum Depth of Binary Tree)题解

Maximum Depth of Binary Tree 是 LeetCode Hot 100 里面一道非常经典的二叉树递归题。

这道题表面上非常简单,很多人第一次看到时都会觉得:

不就是求一棵树有多高吗?

确实,从题意上看,这题并不复杂。 但它之所以经典,不是因为题目难,而是因为它几乎是学习二叉树递归时最基础、最标准的一道模板题。

你给出的这份 Java 代码,使用的是这道题最经典的一种写法:

递归

而且这段代码非常简洁,几乎把“树的递归定义”直接翻译成了程序:

  • 空树的深度是 0

  • 一棵树的最大深度 = 左子树最大深度 和 右子树最大深度 中的较大值,再加上当前根节点这一层

本文就结合这段代码,系统地讲一下这道题的思路。


题目介绍

给定一个二叉树的根节点 root,要求你返回这棵树的 最大深度

所谓最大深度,指的是:

从根节点到最远叶子节点的最长路径上的节点数。

注意这里说的是“节点数”,不是边数。

例如下面这棵树:

      3
     / \
    9  20
      /  \
     15   7

它的最大深度是:

3

因为从根节点 3 到最远叶子节点 157 的路径上,一共有 3 个节点:

3 -> 20 -> 15

或者:

3 -> 20 -> 7

示例

示例 1

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

因为树的最长路径从根到最深叶子节点一共经过 3 个节点。

示例 2

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

因为从根节点 1 到叶子节点 2 一共经过 2 个节点。


什么叫“最大深度”?

这题最容易混淆的一点,是“深度”和“高度”的口语理解。 不过在算法题里,通常我们可以这样记:

  • 一棵空树深度为 0

  • 一个只有根节点的树,深度为 1

  • 每往下一层,深度就加一

所以对于一棵树来说:

最大深度,就是看它最深能走到第几层。

例如:

    1
   /
  2
 /
3

这棵树的最大深度就是:

3

因为最深的节点 3 在第 3 层。


为什么这道题特别适合递归?

因为二叉树本身就是递归结构。

对于一棵树来说:

  • 它的左子树本身也是一棵树

  • 它的右子树本身也是一棵树

而要求“整棵树的最大深度”,其实就可以拆成:

  • 求左子树的最大深度

  • 求右子树的最大深度

  • 取其中较大的那个

  • 再加上当前根节点这一层

你会发现,这种定义天然就非常适合递归。

这也是为什么这题经常被当作二叉树递归入门模板题。


核心思路

我们先想一个最关键的问题:

如果已经知道左子树和右子树的最大深度,那么当前树的最大深度怎么求?

答案非常直接:

maxDepth(root) = max(左子树深度, 右子树深度) + 1

为什么要 +1

因为左子树和右子树的深度,都是从它们各自根节点开始算的。 而当前整棵树还要把当前这个根节点自己也算进去,所以要再加一层。

另外,递归一定要有终止条件。 这里最自然的终止条件就是:

如果当前节点为空,深度就是 0

于是整道题的递归逻辑就完整了。


Java 代码

下面是你给出的代码,我这里保留原始逻辑,并加上注释:

class Solution {
    public int maxDepth(TreeNode root) {
        // 空树深度为 0
        if (root == null) return 0;

        // 当前树的最大深度 = 左右子树最大深度中的较大值 + 1
        return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1;
    }
}

代码拆解

这段代码非常短,但它几乎就是“树的递归定义”本身。 下面一步一步来看。


1. 为什么空节点返回 0?

if (root == null) return 0;

因为空树没有任何节点,所以它的深度自然是 0

这一步既符合题意,也构成了递归终止条件。 如果没有这句,递归就无法停下来。

而且这个定义也非常自然:

  • 空树深度为 0

  • 只有一个根节点的树,深度就是 1

  • 再往上就能一层层推出来

所以这是这题最基础、最关键的边界条件。


2. 为什么结果是 Math.max(maxDepth(root.left), maxDepth(root.right)) + 1

return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1;

因为对于当前节点 root 来说:

  • 左子树的最大深度是 maxDepth(root.left)

  • 右子树的最大深度是 maxDepth(root.right)

而整棵树的最大深度,只取决于较深的那一边。

所以要先取:

Math.max(...)

然后再加上当前根节点这一层:

+ 1

这就是这道题最核心的状态转移。


手动模拟一遍

我们用经典例子来走一遍:

      3
     / \
    9  20
      /  \
     15   7

调用:

maxDepth(3)

处理节点 3

它会先去求:

  • maxDepth(9)

  • maxDepth(20)

然后取较大值,再加 1。


处理节点 9

节点 9 没有左右孩子,所以:

  • maxDepth(null) = 0

  • maxDepth(null) = 0

于是:

maxDepth(9) = max(0,0) + 1 = 1

处理节点 20

节点 20 需要继续求:

  • maxDepth(15)

  • maxDepth(7)


处理节点 15

15 没有左右孩子,所以:

maxDepth(15) = 1

处理节点 7

同理:

maxDepth(7) = 1

于是:

maxDepth(20) = max(1,1) + 1 = 2

回到节点 3

现在已经知道:

  • 左子树深度 = 1

  • 右子树深度 = 2

所以:

maxDepth(3) = max(1,2) + 1 = 3

最终答案就是:

3

为什么这个方法是正确的?

因为一棵树的最大深度,本质上就是:

从根节点出发,左右两边谁更深,就沿着谁往下走,并把当前节点这一层也算进去。

而递归恰好完整地模拟了这个过程:

  • 先递归算出左子树深度

  • 再递归算出右子树深度

  • 取较大值

  • 加上当前节点

此外:

  • 空树深度定义为 0

  • 单节点树深度自然是 1

所以这个递归定义和题目要求完全一致,因此一定正确。


复杂度分析

假设二叉树一共有 n 个节点。

时间复杂度

每个节点都会被访问一次,所以时间复杂度是:

O(n)

空间复杂度

额外空间主要来自递归调用栈。

最坏情况下,如果树退化成链表,递归深度会达到 n,所以空间复杂度是:

O(n)

如果树比较平衡,那么递归深度大约是树高:

O(log n)

但通常最坏情况写作 O(n)


这道题真正想考什么?

这道题表面上不难,但它特别适合考察“你是否真正理解树递归”。

第一,是否能把树问题拆成左右子树问题

这是树递归最核心的能力。 只要你能想到:

当前答案 = 左子树答案 和 右子树答案 的某种组合

很多树题就会变得很自然。

第二,是否会写正确的递归终止条件

像这题里:

if (root == null) return 0;

这种边界看起来简单,但它是整段递归成立的基础。

第三,是否理解“当前层”为什么要加 1

很多初学者会把这一步忘掉。 但实际上,左右子树的深度只描述下面的层数,当前节点自己这一层也必须算进去。


这题还有别的写法吗?

有。

除了递归写法之外,这题还可以用:

层序遍历(BFS)

来做。

思路是:

  • 用队列一层一层遍历树

  • 每遍历完一层,深度加一

  • 最后得到总层数

这种写法也很经典。

不过从简洁程度和递归结构的自然性来说,你现在这份递归代码是最适合作为主解法的。


和“二叉树的层序遍历”有什么关系?

前一题你写的是层序遍历,那题用的是 BFS。 而这题用的是递归 DFS。

它们虽然都能解决树问题,但角度不同:

层序遍历

关注的是:

  • 每一层有哪些节点

最大深度

关注的是:

  • 这棵树总共有多少层

  • 哪条路径最深

所以这题更适合用 DFS 从下往上返回答案,而不是单纯地按层收集节点。


和“二叉树的最小深度”有什么区别?

这两题特别容易一起出现。

最大深度

max(左深度, 右深度) + 1

最小深度

不能简单写成:

min(左深度, 右深度) + 1

因为如果某一边为空,另一边不空,这样会出错。

所以“最大深度”这题虽然简单,但它也在帮你建立一个很重要的树递归基础,为后面的“最小深度”等题做准备。


总结

这道题的核心思想可以概括成一句话:

一棵二叉树的最大深度,等于它左右子树最大深度中的较大值,再加上当前根节点这一层。

具体做法就是:

  1. 如果当前节点为空,返回 0

  2. 递归求左子树最大深度

  3. 递归求右子树最大深度

  4. 返回两者较大值加一

代码非常简洁:

class Solution {
    public int maxDepth(TreeNode root) {
        if (root == null) return 0;
        return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1;
    }
}

这是一道非常经典、也非常值得认真理解的二叉树基础题。 因为它会让你真正体会到:

  • 树递归为什么天然适合“左右子树拆分”

  • 边界条件在递归里有多重要

  • 很多看似复杂的树问题,本质上都能写成很短的一行递推

把这道题真正吃透之后,再去看:

  • 二叉树的最小深度

  • 平衡二叉树

  • 直径

  • 路径总和

这些树递归题时,你会明显更容易抓住它们的共同结构。

因为“二叉树的最大深度”本身就是二叉树递归入门里最经典的一道模板题。

如果对您有帮助的话,能否支持一下博主?
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇