当前:LC543 · 二叉树的直径 · 首次出现于 Day 22 · 路径:顶栏「56天打卡」→ 点击 LC 题号 → 逐题动画

LC543 · Diameter of Binary Tree · 树

二叉树的直径:某节点左右深度加起来

任意两点路径都有一个最高的折点。经过这个节点的最长路径,边数等于左子树深度加右子树深度。直径是所有节点上这个和的最大值,不一定过根。

对每个节点,经过它的最长路径边数 = 左深度 + 右深度。后序递归返回深度 1+max(左,右),返回前用左+右挑战全局 best。空节点深度 0。时间 O(n),空间 O(h)。

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

给你一棵二叉树的根,返回它的直径:任意两个节点之间路径的边数最大值。路径可以不经过根。

主例层序 [1, 2, 3, 4, 5]:根 1,左 2 下挂 4 和 5,右是叶子 3。最长路径是 4-2-1-3 或 5-2-1-3,都是 3 条边;4-2-5 只有 2 条。答案 3。

只算根的左右深度会漏掉「最长路完全藏在某一棵子树里」的情况。本文要回答:为什么每个节点都要看一眼左深加右深,以及求深度的那次遍历怎样顺手记下答案。

最长路必过一个折点,折点处就是左右深之和

树上任意两点之间只有一条简单路径。把这条路径上深度最浅的节点叫做折点:从它往一边下到一个端点,往另一边下到另一个端点。于是经过节点 v 的路径,最长能有多长,完全取决于 v 左边能走多深、右边能走多深。边数就是左深度加右深度,不要再加 1——深度已经按边数计。

直径是「所有这样的折点里,左深+右深最大的那个」。折点可以是根,也可以不是。主例根上 2+1=3,节点 2 上 1+1=2,叶子上 0+0=0,最大是 3,过根。若把 3 换成一棵很高的右子树、同时把 2 的两侧再加长且超过根的两侧,最大和就会落在 2 上,根不再是折点。只算根会错。

深度从空算起是 0,叶子是 1。这里的深度是「从该节点向下走到最远叶子的边数」,和 LC104 的最大深度同一尺度。不要和「节点个数」混:左深 2 加右深 1 是 3 条边、4 个节点。

直径按边数题目要的是边的条数,不是节点个数。左深+右深已经是边数。返回给父节点的高度才需要再加 1。

后序先问左右深,加起来更新,再把高度交上去

每个节点本来就要知道左右子树有多深,才能算出自己的高度。缺的只是在交高度之前多看一眼:cand = 左深 + 右深,拿去挑战全局 best。同一趟后序既服务父节点要的高度,又服务直径要的和。先写一个算高度的函数,再对每个节点重算左右深,同一条边会走许多遍,最坏平方。

约定空节点返回 0。当前节点先递归左右,得到 l、r,立刻 best = max(best, l+r),然后返回 1+max(l,r)。更新必须写在返回前:父节点拿到的是高度,看不到这次的 l+r;不在这里记,这个折点就丢了。

用手走主例。叶子 4、5、3 左右都是 0,候选 0,高度 1。节点 2:左 1、右 1,候选 2,高度 2。根 1:左 2、右 1,候选 3,高度 3。best 停在 3。演示第一帧站在根,标出左高 2、右高 1、候选 3;第二帧回到节点 2,候选 2 打不过 3。路径 4-2-1-3 正好用上根的两侧。

单节点直径 0,不是 1。全是左链时每个节点右深都是 0,候选等于左深,直径退化成这条链的边数。best 必须在函数外累加,递归只返回高度——若把直径当返回值,父节点就没法再拿高度往上加。

每个节点:直径候选 = 左高 + 右高
12345
2 → 高 23 → 高 11 → 高 3
候选 = 左高+右高 = 3直径 = 3
根:左高2 + 右高1 = 3

Go:后序求高 + 更新直径

solution.goGo
func diameterOfBinaryTree(root *TreeNode) int {
best := 0
var depth func(*TreeNode) int
depth = func(n *TreeNode) int {
if n == nil { return 0 }
l, r := depth(n.Left), depth(n.Right)
best = max(best, l+r)
return 1 + max(l, r)
}
depth(root)
return best
}

1best 在闭包外,记下所有折点上左深+右深的最大。

2空返回 0。叶子左右都是 0,候选 0,高度 1。

3先更新直径,再返回高度。两行对调不影响正确性,但父节点永远不该收到直径。

4主例根上 l=2、r=1,best 写成 3;节点 2 上 1+1=2,不刷新。

总结

经过某节点的最长边数 = 左深 + 右深;后序求深时取最大。主例根上 3,答案 3。

  • 直径不一定过根。每个节点都要算一次左+右。
  • 返回给父节点的是高度 1+max(l,r),不是直径。
  • 单节点答案 0。深度按边,空是 0。
同族题目
LC104二叉树的最大深度LC110平衡二叉树LC124二叉树中的最大路径和