【LeetCode-00124】二叉树中的最大路径和 [难度:困难]

176 阅读3分钟

原题

L00124二叉树的最大路径和
   路径 被定义为一条从树中任意节点出发,沿父节点-子节点连接,达到任意节点的序列。同一个节点在一条路径序列中 至多出现一次 。该路径 至少包含一个 节点,且不一定经过根节点。
   路径和 是路径中各节点值的总和。 给你一个二叉树的根节点 root ,返回其 最大路径和 。

输入:root = [1,2,3]
输出:6
解释:最优路径是 2 -> 1 -> 3 ,路径和为 2 + 1 + 3 = 6


输入:root = [-10,9,20,null,null,15,7]
输出:42
解释:最优路径是 15 -> 20 -> 7 ,路径和为 15 + 20 + 7 = 42

解法

  有题目可知道,节点的最大路径和 : 取决于该节点的值与该节点的左右子节点的最大贡献值!

  • 题意可知,最大路径和,是可能产生于其中一个子树中的;
  • 所以每递归一个子树,都求一下当前子树内部的最大路径和;
  • 注意: 一个子树内部的路径,要包含当前子树的根节点。如果不包含,那还算什么属于当前子树的路径,那就是当前子树的子树的内部路径了。
  • 所以,一个子树内部的最大路径和 = 左子树提供的最大路径和 + 根节点值 + 右子树提供的最大路径和。即dfs(root.left)+root.val+dfs(root.right)

  所以,我们只需获取孩子最大贡献值!即:递归计算左右子节点的最大贡献值
下面两种代码思路(其实总体思想一致):
方式一

public class L00124MaxPathSum {
    int result = Integer.MIN_VALUE;

    public int maxPathSum(TreeNode root){
        dfs(root);
        return result;
    }

    /**
     *方式一内存40。3MB,时间1ms
     * @param root
     * @return
     */
    public int dfs(TreeNode root){
        //如果root为叶子结点,则贡献为0
        if (root==null){
            return 0;
        }
        //如果不是叶子结点,则计算它的左右孩子的最大对自身的贡献leftValue 和 rightValue
        int leftValue = dfs(root.left);
        int rightValue = dfs(root.right);
        //更新最大值,就是当前结点val加上左右结点的贡献
        result = Math.max(result,root.val+leftValue+rightValue);
        //计算当前结点能为父节点提供的贡献,记得加上自身贡献val
        int max = Math.max(root.val+leftValue,root.val+rightValue);
        //如果贡献小于0,则返回0
        return max<0?0:max;
    }
}

方式二

public class L00124MaxPathSum {
    int result = Integer.MIN_VALUE;

    public int maxPathSum(TreeNode root){
        maxGain(root);
        return result;
    }

     /**
     * 方式二优化方式一,减少了内存消耗 40MB
     * @param root
     * @return
     */
    public int maxGain(TreeNode root){
        //如果是子节点则贡献为0
        if (root == null){
            return 0;
        }
        //递归计算左右子节点的最大贡献值
        //只有在大于0时,才会选取对应结点
        int leftGain = Math.max(maxGain(root.left),0);
        int rightGain = Math.max(maxGain(root.right),0);

        //节点的最大路径和取决于该节点的值与该节点的左右子节点的最大贡献值
        int priceNewpath = root.val+leftGain+rightGain;
        //更新答案
        result = Math.max(priceNewpath,result);
        //返回结点最大贡献值
        return root.val+Math.max(leftGain,rightGain);
    }
}