LEETCODE 104Easy
二叉树的最大深度
把整棵树的深度拆成子树的深度加一,递归就成了对定义的直接翻译。
问题拆解
题目要的是根节点到最远叶子的路径上有多少个节点。第一反应可能是去枚举所有从根到叶子的路径,比较谁最长,但这样既要记录路径又要回溯,写起来很啰嗦。
真正的关键是换一个视角:一棵树的最大深度,等于它两棵子树中较深那棵的深度,再加上根节点自己这一层。
深度这个量对整棵树的定义,和对任意子树的定义完全一样。这正是递归能生效的信号。
后序递归
先算出左右子树的深度,再合并成当前树的答案——这是典型的后序处理顺序:
def maxDepth(root):
if not root:
return 0
return 1 + max(maxDepth(root.left), maxDepth(root.right))
空树的深度是 0,这既是递归的终点,也让叶子节点自然得到 1 + max(0, 0) = 1。整个函数几乎就是把「深度 = 较深子树 + 1」这句话原样抄成了代码。
如果担心极端瘦长的树把递归栈压爆,可以改用层序遍历,一层一层往下数,遍历了几层深度就是几。但对本题的数据规模,递归写法足够清晰。
复杂度
| 指标 | 复杂度 | 原因 |
|---|---|---|
| 时间 | O(n) |
每个节点恰好被访问一次 |
| 空间 | O(h) |
递归栈深度等于树高,最坏退化成 O(n) |
可以迁移的模式
- 当一个量「对整体的定义」和「对局部的定义」一致时,优先考虑递归;
- 后序处理适合「答案要靠孩子先算好再汇总」的场景;
- 空节点返回一个恰当的边界值(这里是
0),能让叶子的计算无需特判。
先想清楚返回值代表什么,再写递归体,往往比先写代码再补语义顺得多。