maxpathsum不能只靠一次递归返回值解决,因为路径可跨根(左→根→右),而递归只能返回一条单向路径;必须用全局变量捕获跨根路径和,递归函数职责单一:返回以当前节点为起点向下的最大单边和(必含当前节点,子路径可舍弃)。

为什么maxPathSum不能只靠一次递归返回值解决
因为路径可以跨过根节点(左→根→右),但递归函数每次只能向上返回一条单向路径(比如从子树出发,经根,往父节点走)。这意味着:递归返回值必须是「以当前节点为起点向下延伸的最大单边和」,而真正的最大路径和可能藏在某个中间节点的「左+根+右」组合里——这个值没法传上去,只能用全局变量捕获。
常见错误是写成:return max(left, right) + root->val,这漏掉了跨根路径;或者试图用返回值同时表达两种语义,导致逻辑混乱。
- 递归函数职责必须单一:只算「单向路径最大和」(可为空,即取0)
- 每次进入节点时,立刻用
left + right + root->val更新全局最大值 - 空子树贡献按0处理(允许路径不包含某侧),但注意:节点值本身可能为负,所以不能无条件丢弃
maxGain函数里要不要强制包含当前节点
要。这是设计契约:该函数定义为「以当前节点为路径顶端,能向下延伸出的最大单边和」,所以当前节点必选。否则无法统一处理负值场景——比如子树全负,但当前节点是-1,那最优单边就是只取自己(-1),而不是加一个更负的子树。
实现上就是:max(0, left_gain) + root->val,其中max(0, ...)表示允许放弃整条子路径(即路径在此截断),但当前节点不可跳过。
- 如果
left_gain为负,max(0, left_gain)取0,相当于单边路径只含当前节点 - 不能写成
max({0, left_gain, right_gain}) + root->val——那是错的,因为单边路径只能选左或右之一,不是三选一 - 该设计天然支持叶子节点:左右均为0,返回
root->val
全局变量max_sum初始化为什么不能是0
因为所有节点值可能全为负,比如[-2, -1],正确答案是-1,但如果初始化max_sum = 0,最终结果会错误地卡在0。必须设为最小可能值,如INT_MIN。
另一个坑是:有人用指针或引用传参模拟全局变量,但在多层递归中容易因作用域或生命周期搞混;直接用类成员变量或lambda捕获的引用更稳。
- C++中推荐:在类内声明
int max_sum = INT_MIN;,在主函数调用前重置 - 若用纯函数式写法(无类),可用
static int max_sum,但要注意多次调用时残留值问题 - 别依赖「第一次访问节点时赋值」这类逻辑,易漏边界(如空树)
空树和单节点的边界怎么自然覆盖
递归基写成if (!root) return 0;就足够。空树返回0,意味着「不贡献任何值」,上层计算left + right + root->val时,空子树不影响加法;而单节点树,左右返回0,路径和就是0 + 0 + root->val,直接参与全局更新。
不需要额外判断节点数,也不需要特殊处理root->left == nullptr && root->right == nullptr——那个逻辑已隐含在递归结构里。
- 空树输入时,
max_sum保持INT_MIN,但主函数应检查并返回0或抛异常?取决于题意;LeetCode默认非空,通常不需判空 - 若题目允许空路径(和为0),才需要调整逻辑,但本题「路径至少含一个节点」,所以空树不应触发更新
- 所有运算基于
int,注意溢出风险小,但INT_MIN作为初值必须匹配类型
最易被忽略的是:更新全局最大值的位置必须在递归内部、左右子树结果拿到之后,且必须用未加当前节点的子树增益(即left_gain和right_gain)来算跨根路径;一旦和返回逻辑混在一起,比如在return前才更新,就可能把已截断(取0)的值误用于跨根计算。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











