Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LeetCode 124. Binary Tree Maximum Path Sum #18

Open
Woodyiiiiiii opened this issue Apr 19, 2020 · 0 comments
Open

LeetCode 124. Binary Tree Maximum Path Sum #18

Woodyiiiiiii opened this issue Apr 19, 2020 · 0 comments

Comments

@Woodyiiiiiii
Copy link
Owner

Woodyiiiiiii commented Apr 19, 2020

Given a non-empty binary tree, find the maximum path sum.

For this problem, a path is defined as any sequence of nodes from some starting node to any node in the tree along the parent-child connections. The path must contain at least one node and does not need to go through the root.

Example 1:

Input: [1,2,3]

       1
      / \
     2   3

Output: 6

Example 2:

Input: [-10,9,20,null,null,15,7]

   -10
   / \
  9  20
    /  \
   15   7

Output: 42

这题我不会,看了大神的做法:

    4
   / \
  11 13
 / \
7   2
由于这是一个很简单的例子,很容易就能找到最长路径为 7->11->4->13,那么怎么用递归来找出正确的路径和呢?
根据以往的经验,树的递归解法一般都是递归到叶节点,然后开始边处理边回溯到根节点。
这里就假设此时已经递归到结点7了,其没有左右子节点,如果以结点7为根结点的子树最大路径和就是7。
然后回溯到结点 11,如果以结点 11 为根结点的子树,最大路径和为 7+11+2=20。
但是当回溯到结点4的时候,对于结点 11 来说,就不能同时取两条路径了,只能取左路径,或者是右路径,所以当根结点是4的时候,那么结点 11 只能取其左子结点7,因为7大于2。
所以,对于每个结点来说,要知道经过其左子结点的 path 之和大还是经过右子节点的 path 之和大。
递归函数返回值就可以定义为以当前结点为根结点,到叶节点的最大路径之和,然后全局路径最大值放在参数中,用结果 res 来表示。

在递归函数中,如果当前结点不存在,直接返回0。
否则就分别对其左右子节点调用递归函数,由于路径和有可能为负数,这里当然不希望加上负的路径和,所以和0相比,取较大的那个,就是要么不加,加就要加正数。
然后来更新全局最大值结果 res,就是以左子结点为终点的最大 path 之和加上以右子结点为终点的最大 path 之和,还要加上当前结点值,这样就组成了一个条完整的路径。
而返回值是取 left 和 right 中的较大值加上当前结点值,因为返回值的定义是以当前结点为终点的 path 之和,所以只能取 left 和 right 中较大的那个值,而不是两个都要,参见代码如下:
class Solution {
public:
    int maxPathSum(TreeNode* root) {
        int res = INT_MIN;
        helper(root, res);
        return res;
    }
    int helper(TreeNode* node, int& res) {
        if (!node) return 0;
        int left = max(helper(node->left, res), 0);
        int right = max(helper(node->right, res), 0);
        res = max(res, left + right + node->val);
        return max(left, right) + node->val;
    }
};

因为Java的基本数据类型是值传递,所以res不能作为参数,应该命名为属性。

class Solution {
    int res = Integer.MIN_VALUE;
    public int maxPathSum(TreeNode root) {
        helper(root);
        return res;
    }
    int helper(TreeNode node) {
        if (node == null) {
            return 0;
        }
        int left = Math.max(helper(node.left), 0);
        int right = Math.max(helper(node.right), 0);
        res = Math.max(res, left + right + node.val);
        return Math.max(left, right) + node.val;
    }
}

采用后序遍历的方式,返回值是当前节点数值加上它的最大的子树路径,第二个参数记录res是以左子结点为终点的最大 path 之和加上以右子结点为终点的最大 path 之和,还要加上当前结点值,这样就组成了一个条完整的路径。
实际上这是树形DP的套路,不用创建新结构,从左子树收集信息,从右子树收集信息,在当前根节点处整合。不同的是整合后返回上一级的值跟总信息不同,前者代表一条非终结路径数值之和,后者时完整路径数值之和。

res = max(res, left + right + node->val);

这段代码是在当前节点对左右信息的整合,获取最大路径。而下面一段代码返回的是取最大子树路径加上当前节点值,以便回溯上一级时作为一部分最大子树路径(变量left or right)。

还有一点,为什么要与0比较呢?

int left = Math.max(helper(node.left), 0);
int right = Math.max(helper(node.right), 0);

因为如果当前最大路径比0还小,那该路径不在选择之中,即路径选择一边就够了,而不是有折点的。如果左右两条路径都为负,那么选择根节点作为最大路径即可。比如二叉树根节点为1,左子树节点值为-1,右子树为-2,那么返回1。

Tips:
类似的多叉树树状DP求path问题:


参考资料:

  1. LeetCode原题
  2. [LeetCode] 124. Binary Tree Maximum Path Sum grandyang/leetcode#124
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant