leetcode 124 二叉树中的最大路径和@TOC
解题思路:动态规划
每一条路径,一定是先上升0 ~ n个节点,到达顶点,然后下降0 ~ n个顶点。换言之,每一个节点都可以作为顶点,并有一条最佳路径。
有一个类似的题目,求数组的最长子数组。dp[i]表示以nums[i]为结尾时的最大子数组和。
针对二叉树的最大路径和,可以用dp[I]表示以I为顶点时的最大路径和。
因此为求得最大路径和,就需要遍历每一个节点,求每一个dp[I]。联想到的第一个就是递归。递归函数可以表示以root为顶点结尾时的最大路径,返回值代表root作为子节点时的最长路径。
class Solution {
private:
int MAXSUM = INT_MIN;
public:
int maxSum(TreeNode* root) { //maxSum以root为根节点结尾时的最大路径,返回值是root作为子节点时的最长路径
if (root == NULL) return 0;
int leftSum = max(maxSum(root->left), 0);
int rightSum = max(maxSum(root->right), 0);
int nowSum = leftSum + rightSum + root->val;
MAXSUM = max(MAXSUM, nowSum);
return max(leftSum, rightSum) + root->val; //
}
int maxPathSum(TreeNode* root) {
maxSum(root);
return MAXSUM;
}
}
参考leetcode评论区的一个大佬的思路:
这题目的难点在于理解题意和转化题意。
我们可以结合 数组的最大子数组和 的思路去解题。
-
「可以从任意节点出发, 到达任意节点」 的路径,
一定是先上升( 0 ~ n 个)节点, 到达顶点, 后下降( 0 ~ n 个)节点。
我们可以通过枚举顶点的方式来枚举路径。 -
我们枚举顶点时, 可以把路径分拆成3部分: 左侧路径、右侧路径和顶点。
如下面的路径, 顶点为 20, 左侧路径为 6 -> 15, 右侧为 6 -> 7。-10
/
9 [20]
/
[15] [7]
/ /
[6] 4 [6]以当前节点为顶点的路径中, 最大和为 两侧路径的最大和 + 节点的值。
需要注意的是, 两侧路径也可能不选, 此时取 0。 -
如何求两侧路径最大和? 看一个类似问题:求数组的最大子数组和。
动态规划: dp[i] 代表以 nums[i] 为结尾的子数组的最大和。
转移方程: dp[i] = max(dp[i-1], 0) + nums[i]。 -
在树上, 设 dp[C] 代表以当前节点为结尾的最大上升路径和,
则我们需要对节点的左右子树做一个选择, 有
dp[C] = max(max(dp[L], 0), max(dp[R], 0)) + C.val
式中, C,L,R 分别代指 当前节点、左子节点、右子节点。 -
最后, 以当前节点为顶点的路径中, 最大的和为
max(dp[L], 0) + max(dp[R], 0) + C.val。
我们枚举顶点, 并记录最大答案。