#124
困难
高频
递归 DFS二叉树中的最大路径和
这是一道围绕树、二叉树展开的高频练习。建议先掌握「递归 DFS」这套写法,再结合下方步骤讲解理解状态维护、边界处理和复杂度取舍。
树
二叉树
题目分析
给你一棵二叉树,要求找出一条路径,使路径上节点值之和最大,并返回这个最大和。
这里的路径不要求经过根节点,但路径必须沿着父子关系连接,而且不能重复经过节点。
一句话概括:
每个节点都可能成为一条最大路径的“拐点”,答案要在全树范围内比较。
接下来怎么看推荐代码: 带着这个理解再看推荐代码时,重点观察这条主线:递归计算每个节点向下延伸的最大贡献值,同时用“左贡献 + 节点值 + 右贡献”更新全局最大路径和。
推荐代码
推荐解法:递归 DFS
时间复杂度: O(n)
空间复杂度: O(h)
核心思路: 递归计算每个节点向下延伸的最大贡献值,同时用“左贡献 + 节点值 + 右贡献”更新全局最大路径和。
class Solution {
private int maxSum = Integer.MIN_VALUE;
public int maxPathSum(TreeNode root) {
maxGain(root);
return maxSum;
}
private int maxGain(TreeNode node) {
if (node == null) {
return 0;
}
// 递归计算左右子树的最大贡献值
// 只有当贡献值大于0时,才会选择该子树
int leftGain = Math.max(maxGain(node.left), 0);
int rightGain = Math.max(maxGain(node.right), 0);
// 计算当前节点的最大路径和
// 路径是:左子树 -> 当前节点 -> 右子树
int currentPathSum = node.val + leftGain + rightGain;
// 更新全局最大路径和
maxSum = Math.max(maxSum, currentPathSum);
// 返回当前节点对父节点的最大贡献值
// 只能选择左子树或右子树中的一条路径
return node.val + Math.max(leftGain, rightGain);
}
}
// 二叉树节点定义
class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode() {}
TreeNode(int val) { this.val = val; }
TreeNode(int val, TreeNode left, TreeNode right) {
this.val = val;
this.left = left;
this.right = right;
}
}结构化讲解
面试时怎么讲
开场思路
这题我会把递归返回值和全局答案分开处理:返回单边贡献,更新完整路径。
核心过程
- 递归计算左右子树向上的最大贡献,负值直接舍弃。
- 以当前节点为拐点,尝试用左右贡献加当前值更新全局最大路径和。
- 然后向父节点返回当前节点能提供的单边最大贡献。
- 整棵树遍历完后,全局变量里保存的就是答案。
复杂度总结
时间复杂度 O(n),空间复杂度 O(h)。
面试补一句:这题最重要的区分是:更新答案用双边,返回父节点用单边。
核心思路
最大路径和有两个层面:对父节点来说,只能接一边向上的最大贡献;但对全局答案来说,当前节点可以把左右两边都接起来形成一条完整路径。
步骤讲解
1
先算左右子树向上的最大贡献
递归得到左右子树能向当前节点提供的最大贡献值,负贡献直接当 0。
为什么这样做:负数只会拖累路径和,不如直接舍弃。
对应代码提示:int leftGain = Math.max(dfs(node.left), 0);
2
用当前节点做路径拐点更新全局答案
把 leftGain + node.val + rightGain 作为经过当前节点的完整路径和,更新全局最大值。
为什么这样做:全局最佳路径可能在当前节点同时连接左右两侧。
对应代码提示:answer = Math.max(answer, leftGain + node.val + rightGain);
3
向上只返回单边最大贡献
给父节点时,只能返回当前节点值加上左右贡献中较大的一边。
为什么这样做:路径向上延伸时不能同时分叉走两边。
对应代码提示:return node.val + Math.max(leftGain, rightGain);
易错点
向父节点返回左右两边总和
这会让路径在向上时出现分叉,违反路径定义。
正确理解:返回值只能是单边贡献,双边和只用于更新全局答案。
没把负贡献截成 0
负路径会拉低总和,影响最优答案。
正确理解:对子树贡献先做
Math.max(gain, 0) 处理。把根到叶路径和当成答案
本题路径不要求经过根节点,也不要求终点是叶子。
正确理解:全局答案要在每个节点处尝试更新,不局限于根路径。
复杂度与适用判断
时间复杂度:O(n)
空间复杂度:O(h)
比其他方案更好在哪里:比枚举所有路径高效得多,也是树上路径类题的经典 DFS 模板。
适用判断:树题出现“最大路径/最大贡献/经过节点的最优值”时,优先考虑递归返回贡献值。
额外提醒
- 全局答案和递归返回值的含义不同,必须分开理解。
动画演示
如果你还没完全看懂,可以展开动画演示。
递归 DFS动画演示
想看这段解法是怎么一步步运行的,可以展开动画继续观察。
递归 DFS动画演示
想看这段解法是怎么一步步运行的,可以展开动画继续观察。
二叉树中的最大路径和 - 递归DFS
当前最大路径和: -9007199254740991
操作日志
动画演示仅在桌面端提供,移动端请优先阅读推荐代码与结构化讲解。