二叉树中最大路径和
一、写在前面
它的难,并不在于写出 DFS,而在于:
1. 路径可以不经过根;
2. 路径可以只含一个节点;
3. 节点值可能为负;
二、题意再翻译
给定一棵二叉树,找出任意一条节点序列,使得:
- 相邻节点必须父子相连;
- 同一节点至多出现一次;
- 序列和最大。
返回这个最大和。
注意:路径可以从任意节点出发,到任意节点结束,不必经过根。
三、示例热身
例 1
1
/ \
2 3
```
最优路径:2 → 1 → 3,和 = 6。
例 2
```
-10
/ \
9 20
/ \
15 7
最优路径:15 → 20 → 7,和 = 42。
---
四、思路拆解:后序 DFS + 全局变量
1. 定义“贡献值”
对于当前节点 `node`,它向上层父亲能做出的最大单边贡献是:
```
node.val + max(0, 左子树贡献, 右子树贡献)
```
如果左/右子树贡献为负,还不如不走那边(取 0)。
2. 拼出“跨越”路径
以 `node` 为拐点的一条完整路径和:
```
node.val + max(0, left) + max(0, right)
```
这条路径不能再往上延伸,否则会分叉。
3. 全局打擂台
用全局变量 `maxSum` 实时更新第 2 步算出的值。
初始设为 `Integer.MIN_VALUE`,防止所有节点都是负数。
4. 返回什么?
只能返回单边最大贡献给父节点,否则就分叉了。
---
五、代码时间(Java)
```java
class Solution {
private int maxSum = Integer.MIN_VALUE;
public int maxPathSum(TreeNode root) {
dfs(root);
return maxSum;
}
private int dfs(TreeNode node) {
if (node == null) return 0;
int left = Math.max(dfs(node.left), 0); // 负贡献直接丢弃
int right = Math.max(dfs(node.right), 0);
int path = node.val + left + right; // 以 node 为拐点的完整路径
maxSum = Math.max(maxSum, path);
return node.val + Math.max(left, right); // 单边贡献
}
}
```
---
六、复杂度分析
- 时间:每个节点仅访问一次 → O(N)
- 空间:递归栈最深树高 → O(H)(H 为树高,最坏链式退化成 O(N))
---
七、常见坑位提醒
1. 全局变量必须初始化为 `Integer.MIN_VALUE`,否则全负树会错。
2. 左右子树贡献为负时,要果断取 0,表示“不选”。
3. 返回给父节点的只能是单边,不能同时带左右两边。
---
八、 debug 小技巧
打印每次 `path` 与 `maxSum`,肉眼追踪第一棵负树:
```
node = -10, path = 42, maxSum = 42
```
看到 `maxSum` 一次性从负值跳到 42,就知道拐点在 `-10` 的右子树,稳!
---
更多推荐


所有评论(0)