【算法】124.二叉树中的最大路径和--通俗讲解
通俗易懂讲解“二叉树的最大路径和”算法题目
一、题目是啥?一句话说清
在二叉树中找一条路径(任意节点序列,每个节点最多有一个父节点和一个子节点),使得路径上所有节点的值之和最大,这条路径不一定经过根节点,但至少包含一个节点。
示例:
- 输入:二叉树,节点值可能为负
- 输出:最大路径和,例如在二叉树
[-10,9,20,null,null,15,7]
中,最大路径和是 42(路径 15 → 20 → 7)
二、解题核心
使用递归方法,从叶子节点开始向上计算每个节点能提供的最大贡献值,同时在每个节点处计算以该节点为顶点的路径和,并更新全局最大路径和。 这就像每个节点向父节点报告“我能为你提供的最大价值是多少”,而父节点则结合左右孩子的报告计算“如果路径以我为中心,总和能有多大”。
三、关键在哪里?(3个核心点)
想理解并解决这道题,必须抓住以下三个关键点:
1. 递归计算节点贡献值
- 是什么:对于每个节点,递归计算以该节点为起点的最大路径和(即从该节点向下延伸的路径,只能选择左或右一条分支)。
- 为什么重要:这提供了节点对父节点的贡献值,帮助父节点计算更长的路径。
2. 更新全局最大路径和
- 是什么:在每个节点处,计算以该节点为顶点的路径和(即节点值 + 左子树贡献 + 右子树贡献),并用此更新全局最大值。
- 为什么重要:最大路径和可能出现在任何节点为顶点的路径上,而不一定是根节点。
3. 处理负值贡献
- 是什么:如果子树的贡献值为负,则选择不包含该子树(即贡献值取0),因为负贡献会减少总和。
- 为什么重要:这确保了路径和不会被负值拖累,从而找到真正的最大值。
四、看图理解流程(通俗理解版本)
让我们用二叉树 [-10,9,20,null,null,15,7]
为例来可视化过程:
-
从叶子节点开始:
- 节点15:左贡献=0,右贡献=0,以15为顶点的路径和=15。报告给父节点的贡献值=max(15,0)=15。
- 节点7:左贡献=0,右贡献=0,以7为顶点的路径和=7。报告贡献值=max(7,0)=7。
-
处理节点20:
- 左贡献=15(来自左子树15),右贡献=7(来自右子树7)。
- 以20为顶点的路径和=20 + 15 + 7 = 42(这是全局最大路径和)。
- 报告给父节点的贡献值=20 + max(15,7) = 20 + 15 = 35(因为只能选一条分支)。
-
处理节点9:
- 左贡献=0,右贡献=0(因为无子树),以9为顶点的路径和=9。
- 报告贡献值=max(9,0)=9。
-
处理根节点-10:
- 左贡献=9(来自左子树9),右贡献=35(来自右子树20)。
- 以-10为顶点的路径和=-10 + 9 + 35 = 34,但34 < 42,所以全局最大值仍是42。
- 报告贡献值=-10 + max(9,35) = -10 + 35 = 25(但25>0,所以报告25?不,实际上如果贡献为负,应该返回0,但这里25是正数)。
注意:在计算贡献值时,如果贡献为负,我们返回0,表示不包含该分支。所以根节点-10的贡献值应该是 max(-10 + max(9,35), 0) = max(25,0)=25?但根据算法,我们直接计算节点值加左右贡献的较大值,但如果结果为负,则返回0。
实际上,在递归函数中,我们计算节点的贡献值时,如果左或右贡献为负,我们就不取(即取0),所以对于根节点-10,贡献值 = -10 + max(左贡献,0) + max(右贡献,0)?不对,递归函数返回的是从该节点向下延伸的最大路径和(只能选一条分支),所以对于根节点,贡献值 = -10 + max( max(左贡献,0), max(右贡献,0) )?但左贡献是9(正),右贡献是35(正),所以贡献值 = -10 + max(9,35) = 25?但25是正数,所以返回25。
但在更新全局最大值时,我们计算以节点为顶点的路径和:节点值 + max(左贡献,0) + max(右贡献,0)。对于根节点,就是 -10 + 9 + 35 = 34。
最终全局最大值是42,来自节点20。
五、C++ 代码实现(附详细注释)
#include <iostream>
#include