LeetCode 543 二叉树的直径:为什么求深度时顺手就能求出直径?
在刷二叉树题目的时候,经常会遇到一个现象:
求最大深度会写,求二叉树直径却总感觉绕。
其实这道题本质上还是一道「求深度」题,只不过在求深度的过程中,多维护了一个全局最大值。
今天就彻底搞懂这道经典面试题。
一、题目描述
给定一棵二叉树,返回它的直径长度。
这里的直径定义为:
任意两个节点之间最长路径的边数。
注意:
- 计算的是边数,不是节点数;
- 最长路径不一定经过根节点。
例如:
1
/ \
2 3
/ \
4 5
最长路径:
4 → 2 → 1 → 3
共有 3 条边,因此答案为:
3
二、先理解什么是深度
对于任意节点:
depth(node)
表示:
以 node 为根的子树最大深度。
例如:
2
/ \
4 5
节点 2 的深度:
max(左子树深度, 右子树深度) + 1
即:
max(depth(node.left), depth(node.right)) + 1
这正是 LeetCode 104 最大深度那道题的核心公式。
三、为什么直径可以用深度求出来?
关键观察:
对于任意一个节点来说:
左子树最深节点
↓
node
↑
右子树最深节点
经过当前节点的最长路径一定是:
左侧最深叶子
↓
当前节点
↑
右侧最深叶子
那么这条路径长度是多少?
答案:
左子树深度 + 右子树深度
例如:
1
/ \
2 3
节点 1:
左深度 = 1
右深度 = 1
经过节点 1 的路径长度:
1 + 1 = 2
刚好对应:
2 → 1 → 3
四、直径真正的本质
经过某个节点的最长路径:
left_depth + right_depth
那么整棵树的直径是什么?
答案就是:
所有节点中
(left_depth + right_depth)
的最大值
换句话说:
diameter = max(
每个节点的左深度 + 右深度
)
因此:
我们只需要遍历整棵树,在计算深度的同时更新最大值即可。
五、递归实现
完整代码:
from typing import Optional
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
class Solution:
def diameterOfBinaryTree(self, root: Optional[TreeNode]) -> int:
max_diameter = 0
def depth(node):
nonlocal max_diameter
if not node:
return 0
left_depth = depth(node.left)
right_depth = depth(node.right)
# 更新当前最大直径
max_diameter = max(
max_diameter,
left_depth + right_depth
)
# 返回当前子树深度
return max(left_depth, right_depth) + 1
depth(root)
return max_diameter
六、代码执行过程
以这棵树为例:
1
/ \
2 3
/ \
4 5
递归过程:
节点4
left = 0
right = 0
更新直径:
0 + 0 = 0
返回深度:
1
节点5
同理:
返回深度 = 1
节点2
此时:
left_depth = 1
right_depth = 1
更新直径:
1 + 1 = 2
返回深度:
max(1,1)+1 = 2
节点3
返回:
1
节点1
此时:
left_depth = 2
right_depth = 1
更新直径:
2 + 1 = 3
最终答案:
3
七、为什么递归返回的是深度而不是直径?
很多同学第一次写这题都会犯这个错误。
递归函数的职责是:
返回当前子树深度
因为父节点需要利用左右子树深度:
left_depth
right_depth
来计算自己的深度。
如果返回直径:
return max_diameter
父节点根本无法计算自己的深度。
所以:
深度负责向上返回
直径负责全局记录
两者职责完全不同。
八、易错点总结
1. 把边数当成节点数
正确:
left_depth + right_depth
错误:
left_depth + right_depth + 1
加 1 后得到的是节点数,不是边数。
2. 只计算根节点
很多人会写:
depth(root.left) + depth(root.right)
直接返回。
这是错误的。
最长路径可能完全位于某棵子树内部。
必须遍历所有节点。
3. 返回值写错
递归函数必须返回:
max(left_depth, right_depth) + 1
而不是返回直径。
4. 忘记 nonlocal
内部函数修改外层变量:
max_diameter
必须声明:
nonlocal max_diameter
否则会出现作用域错误。
九、这道题和最大深度题的关系
很多人刷完这题都会有一个感悟:
二叉树的直径,本质上是「最大深度」题目的升级版。
LeetCode 104:
返回深度
LeetCode 543:
返回深度
+
顺手维护最大直径
所以掌握了最大深度以后,再来看直径问题就会简单很多。
很多二叉树题其实都是这种模式:
递归返回一个值
同时更新一个全局答案
比如:
- 二叉树直径
- 路径和
- 平衡二叉树
- 最大路径和
本质套路完全一致。

155

被折叠的 条评论
为什么被折叠?



