第5章|二叉树与递归

Unit 06 · LeetCode #543 二叉树的直径

← Unit 05
仅本次页面有效
U06
Diameter of Binary TreePostorder · Return Shape · Global Best

向父节点只返回一条路,
在当前节点计算两条路。

直径可能在任意节点完成转向。递归返回值必须保持为父节点还能继续延伸的单支高度;左右两支拼接得到的路径只能更新全局最优,不能直接向上返回。

已恢复上次学习位置环节、动画、答题、代码和编辑器高度均已恢复。
知识桥梁|Unit 05 → Unit 06
Unit 05:两个函数承担两个问题

外层搜索回答“哪里存在”,内层验证回答“当前候选是否成立”。

从双函数分工 → 双输出分工
Unit 06:一个递归产生两种信息

返回值供父节点继续组合;局部候选用于更新整棵树的全局答案。

贯穿本单元的审查问题当前计算出的状态,是“父节点还能继续使用的状态”,还是“已经在当前节点完成的答案候选”?
LeetCode #543 原题路径长度按边数计算

题目要求

给定二叉树根节点 root,返回树中任意两个节点之间最长路径的长度。该路径不一定经过整棵树的根节点。

class Solution: def diameterOfBinaryTree( self, root: Optional[TreeNode] ) -> int: pass
  • 树中节点数为 [1, 10⁴];
  • 路径长度按边数计算。

示例与方法

root = [1,2,3,4,5]
输出:3
root = [1,2]
输出:1

后序 DFS:每个节点得到左右深度,使用 left_depth + right_depth 更新直径,再返回 1 + max(left_depth, right_depth)。时间 O(n),递归栈 O(h)。

单支高度

从当前节点向下,只选择左、右中的一侧,到最远叶子的路径。

候选直径

在当前节点连接左侧最长单支与右侧最长单支,长度为 L+R。

后序递归

先获得左右子树结果,再在当前节点组合并返回。

全局最优

保存所有已处理节点产生的候选直径最大值。

教学树观察当前高亮路径
绿色:完整路径蓝色:向上返回单支紫色:当前候选直径红色:非法分叉返回
递归返回值depth(node) = 1 + max(L,R)

只能保留一侧,供父节点继续延伸。

当前节点候选candidate = L + R

允许连接两侧,但只能更新全局答案。

节点高度与候选直径

调用栈

尚未进入代码轨迹
当前 node—
left_depth / right_depth—
向父节点返回—
全局 diameter0

返回值不变量

depth(node) 始终是一条可继续向父节点延伸的单支路径。

全局答案不变量

diameter 保存所有已处理节点中最大的 L + R。

当前路径节点数0
当前路径边数0
当前候选 L+R—
当前返回高度—
全局直径0
错误实验:把 L+R 返回给父节点

这条路径已经在当前节点分叉。父节点只能通过一条边进入当前节点,不可能同时沿左右两支继续延伸。

代码—树—调用栈联动1 / 1
当前节点—
左右深度—
候选直径—
返回高度—
全局答案0
七个语义槽位先写状态关系,再看完整代码

      
公式审查返回值与答案候选不能混用
向父节点返回

1 + max(left_depth, right_depth)
保持为一条单支路径。

更新全局答案

max(diameter, left_depth + right_depth)
允许在当前节点连接两支。

错误:return L + R

把已经分叉的路径交给父节点,破坏返回值形状。

错误:只在 root 更新

最长路径的转折点可能位于任意内部节点。

迁移目标:LeetCode #124 二叉树中的最大路径和

复用“单支返回+双支更新全局最优”的结构。唯一关键变化是:状态从边数改为节点值贡献,并且负贡献分支应舍弃。

LeetCode #124|二叉树中的最大路径和

标签:树 · DFS · 动态规划
困难

迁移原题

路径由一系列相邻节点组成,每个节点最多出现一次。路径不一定经过根节点。返回任意非空路径的最大节点值之和。

class Solution: def maxPathSum( self, root: Optional[TreeNode] ) -> int: pass

打开 LeetCode #124 原题 ↗

示例与新增约束

root = [-10,9,20,null,null,15,7]
输出:42
root = [1,2,3]
输出:6

负分支会降低路径和,因此贡献使用 max(gain(child), 0)。

复用结构,而不是复用数值公式

#543 已掌握

返回一条单支高度;当前节点连接左右两支更新全局直径。

结构不变 →
#124 新状态

返回一条单支最大贡献;当前节点连接左右正贡献更新全局路径和。

在 #124 中,gain(node) 应向父节点返回什么?

为什么负贡献必须截断为 0?

保留负贡献

例如左分支贡献为 -5,会主动降低当前路径总和。

截断为 0

等价于“不选择该分支”,路径仍可只经过当前节点或另一侧。

当前节点值 20,左贡献 -3,右贡献 7。当前候选路径和是多少?

只补充 #124 相比 #543 的变化槽位

真实轨迹:节点 20 接收 15 与 7 的正贡献

当前 node—
left_gain—
right_gain—
当前候选—
向上返回—
全局 best—

完成 LeetCode 提交代码

参考答案可调整高度或全屏查看
本环节已完成,先停留观察当前状态

继续按钮将在短暂停留后开放,页面不会自动跳转。

环节 1 / 6