当前:LC104 · 二叉树的最大深度 · 首次出现于 Day 16 · 路径:顶栏「56天打卡」→ 点击 LC 题号 → 逐题动画

LC104 · Maximum Depth of Binary Tree · 树

二叉树的最大深度:1 + max(左, 右)

一个节点的深度,是它自己这一层,加上左右子树里更深的那一边。空树先回答 0,数字从叶子往根长。

空节点深度为 0;非空节点深度 = 1 + max(左子树深度, 右子树深度)。后序递归:先得到两个孩子的答案,再给自己加一。时间 O(n),空间 O(h)。

时间 O(n)空间 O(h)结论先行 · 全文约 6 节
导读

给你一棵二叉树的根,返回它的最大深度。深度是从根走到最远那片叶子,沿途经过的节点个数。空树深度是 0,单节点深度是 1。

主例层序 [3, 9, 20, null, null, 15, 7]。根 3,左孩子 9 是叶子,右孩子 20 下面再挂 15 和 7。最远的路是 3 → 20 → 15(或 7),三个节点,答案 3。

本文要回答:为什么不必先层序数层,以及主例里 20 的 2 和根的 3,分别是哪两个子树深度比出来的。

自底向上:先子树后自身

根到最远叶子的节点数,等于「根自己」加上「左右两边更深的那棵子树的深度」。这句话对每一个节点都成立,不只对根成立。缺的不是层序队列,而是一个可以从空节点往上长的数:孩子先交出自己的深度,父亲才能加一。

空节点没有层,深度记 0。叶子左右都是 0,1+max(0,0)=1。内部节点先递归左、再递归右,取较大者加一。这是后序:左右孩子的答案没回来之前,当前节点写不出自己的数。前序先写自己再下探,那时孩子的深度还不知道,加不出来。

用手走主例。15 是叶子,深度 1。7 同样是 1。轮到 20:左右都是 1,1+max(1,1)=2。9 是叶子,深度 1。轮到根 3:左 1、右 2,1+max(1,2)=3。演示场景从 15 记 1,到 20 记 2,到根记 3,标的就是这张自底向上的表。

只数左链或只数右链会在主例上得到 2 或 3 里的某一个,碰巧对,换一棵左深右浅的树就错。层序每层 +1 也能做对,队列里要放下整层节点;递归版只在栈上留一条根到当前节点的路径,空间是树高。两种算法数的是同一个量:最深那条根到叶的节点数。

空树直接 0。一根向左的链,每一层都是 1+max(下一层, 0),深度等于节点数。满二叉树每一层左右一样深,根的深度是层数。每个节点进出一次,没有节点被算两遍。

后序当前节点的深度依赖左右子树的深度,所以必须先问孩子再写自己。这不是风格选择,是数据依赖。
叶子 1,往上累加
3920157
15 → 深度 1
15 是叶子,深度 1

Go:一行递归

solution.goGo
func maxDepth(root *TreeNode) int {
if root == nil { return 0 }
return 1 + max(maxDepth(root.Left), maxDepth(root.Right))
}

1空树返回 0,叶子因此得到 1。主例 15、7、9 都走这一支。

2非空就是自身 1 加上左右递归结果的较大者。20 得到 2,根 3 得到 3。

总结

空树 0,否则 1+max(左深, 右深)。主例根是 1+max(1,2)=3。

  • 必须后序:孩子的深度没回来,父亲加不了一。
  • 单侧计数会在左右不平衡时算错。
  • 层序数层也能做,空间变成一层的宽度。
同族题目
LC110平衡二叉树LC543二叉树的直径LC102二叉树的层序遍历