Skip to content

LeetCode 124. Binary Tree Maximum Path Sum #18

@Woodyiiiiiii

Description

@Woodyiiiiiii

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions