节点收益指以当前节点为起点向下延伸至最多一个子树的最大路径和,仅允许单边;而路径和可跨左右子树。

什么是“节点收益”?它和路径和有什么区别
“节点收益”不是标准术语,而是解题时对 max_gain 的通俗叫法:指**以当前节点为起点,向下延伸(最多到一个子树)所能贡献的最大路径和**。它和最终答案“最大路径和”的关键区别在于:节点收益只允许走单边(左或右),而最大路径和可以跨过当前节点连接左右子树。
比如节点值为 10,左子树最大收益是 5,右子树是 -2,那么它的节点收益是 10 + max(0, 5) = 15(负收益不取),但该节点参与的完整路径和可能是 5 + 10 + (-2) = 13——这正是我们全局更新答案的地方。
常见错误是把两者混为一谈,导致递归返回值写成 root->val + left_gain + right_gain,这会破坏单边约束,后续无法拼接父节点。
递归函数必须返回什么?为什么不能直接更新全局变量
递归函数 max_gain(TreeNode* node) 的返回值必须是“以 node 为起点、向下延伸的单向最大收益”,否则上层无法正确计算自己的收益。它不是求答案,而是为父节点服务的中间结果。
容易踩的坑:
- 误用
void返回类型,只靠全局变量max_sum记录答案——逻辑没错,但丢失了向上回传的关键信息,代码必然出错 - 在递归中对空节点返回 0 是安全的,但要注意:如果子树收益为负,就应截断(即取 0),避免拖累父节点,所以返回值是
max(0, max_gain(child)) - 更新全局最大值的时机必须在递归内部:即计算完左右收益后,立刻尝试
node->val + left_gain + right_gain并更新max_sum
边界与负数处理:空节点、全负数树怎么不出错
空节点返回 0 是通用做法,既简化逻辑,又自然支持“截断负收益”。但要注意全负数场景——此时最大路径和就是最大的那个负数节点,不能返回 0。
关键点在于:全局答案 max_sum 的初值不能设为 0,而应设为 INT_MIN;而每个节点的收益计算中,max(0, ...) 只用于“是否向下延伸”,不影响最终答案的选取。
示例:树为 [-3, -2, -1],根为 -3,左 -2,右 -1。递归中:
-
max_gain(-2)返回max(0, -2) = 0(不往下走) -
max_gain(-1)同样返回 0 - 但更新全局答案时用的是
-3 + 0 + 0 = -3,而右子节点单独路径-1更大,所以max_sum最终为 -1
完整可运行的 C++ 实现要点
核心结构固定,不要增删关键步骤:
- 定义成员变量
int max_sum = INT_MIN,非局部静态,避免多测污染 - 主函数调用
max_gain(root),不直接用其返回值作为答案 -
max_gain函数内:先递归算左右收益,再更新max_sum,最后返回node->val + max(left_gain, right_gain)(注意不是加,是选) - 所有涉及比较的数字都用
max/min,别手写 if,避免漏掉等于情况
最易忽略的是:更新 max_sum 那一行必须放在 return 前,且左右收益要先和 0 取 max 再参与计算——否则负数会错误拉低结果。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











