最大路径和必须用全局变量实时更新,因递归返回值仅表示以当前节点为起点的单向路径和,无法涵盖跨左右子树的“V型”路径;空节点返回0,负子树收益需用max(0,·)提前截断,全局变量初始化为INT_MIN并在后序遍历中更新。

最大路径和不能靠递归函数返回值直接得出,必须用全局变量在每个节点处计算 left_gain + right_gain + root->val 并实时更新——否则像 15→20→7 这种跨左右子树的“V型”路径会彻底丢失。
为什么 dfs() 返回值 ≠ 最大路径和
递归函数语义被严格限定为「以当前节点为起点、向下延伸的单向最大路径和」,它服务于父节点拼接,不是最终答案。如果误把 return max(left, right) + root->val 当作结果,就只拿到了一条分支(比如 20→15 或 20→7),漏掉了 15→20→7 这个完整路径。
-
dfs(root)的返回值永远只能带一条分支上去;带两条就会让父节点路径分叉,违反定义 -
left_gain + right_gain + root->val这个值从不返回,只用于更新全局最大值 - 全负树(如
[-3,-2,-1])下,dfs()可能返回负数,但全局最大值必须捕获其中最大的那个单节点值
max(0, left_gain) 和 max(0, right_gain) 必须提前截断
负子树收益不能留到拼接时再处理——一旦原始负值参与 root->val + left_gain + right_gain 计算,结果就被污染。正确做法是:先拿到原始递归结果,立刻用 max(0, ) 截断,再用截断后的值做后续操作。
- 错误写法:
int l = dfs(node->left); int r = dfs(node->right); max_sum = max(max_sum, node->val + l + r);——若l是 -5,r是 -8,加进去就错 - 正确顺序:
int l = max(0, dfs(node->left)); int r = max(0, dfs(node->right)); max_sum = max(max_sum, node->val + l + r); - 返回值也建议套一层
max(0, node->val + max(l, r)),防止负数上传干扰上层(尤其当node->val本身为负且子树无正贡献时)
空节点返回 0 而不是 INT_MIN
空节点语义是“无贡献”,不是“灾难性拖累”。返回 INT_MIN 会导致加法溢出、max(0, INT_MIN) 在部分平台行为未定义,更重要的是破坏了截断逻辑的直觉一致性。
- 所有递归入口第一行必须是
if (!root) return 0;,否则访问root->left会崩溃 - 单节点树场景下,左右都是
0,root->val + 0 + 0正好把该节点值记入全局最大值 - 全负树中,叶子返回自身负值(如 -3),上层
max(0, -3) == 0,最终root->val + 0 + 0把最大负值(如 -1)成功捕获
全局变量 max_sum 初始化与更新时机
初始化必须为 INT_MIN,且更新必须放在递归体内部、左右子调用之后、返回之前——这是后序遍历“访问根”的天然位置,早了拿不到子树信息,晚了就错过本轮。
- 若初始化为
0,输入[-3]就会返回0,而非正确答案-3 - 更新不能只在根节点或叶子节点做,中间任意节点都可能是路径顶点(如
20在15→20→7中) - 多线程环境下,
max_sum必须改为引用参数传递,否则并发调用会相互覆盖
最易被忽略的其实是语义割裂:你手上有两个数(左收益、右收益),却只能把其中一个喂给父节点,却必须用两个一起算当前层的全局最优。这个矛盾不是设计缺陷,而是路径定义本身决定的——它迫使你把“上传能力”和“本地决策”彻底分开。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











