二叉树的最大深度:1 + max(左, 右)
一个节点的深度,是它自己这一层,加上左右子树里更深的那一边。空树先回答 0,数字从叶子往根长。
空节点深度为 0;非空节点深度 = 1 + max(左子树深度, 右子树深度)。后序递归:先得到两个孩子的答案,再给自己加一。时间 O(n),空间 O(h)。
给你一棵二叉树的根,返回它的最大深度。深度是从根走到最远那片叶子,沿途经过的节点个数。空树深度是 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),深度等于节点数。满二叉树每一层左右一样深,根的深度是层数。每个节点进出一次,没有节点被算两遍。
后序当前节点的深度依赖左右子树的深度,所以必须先问孩子再写自己。这不是风格选择,是数据依赖。
Go:一行递归
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。
- 必须后序:孩子的深度没回来,父亲加不了一。
- 单侧计数会在左右不平衡时算错。
- 层序数层也能做,空间变成一层的宽度。