二叉树中的最大路径和

二叉树中的最大路径和

1、参考资料

https://leetcode-cn.com/problems/binary-tree-maximum-path-sum/

2、题目要求

题目要求:

给定一个非空二叉树,返回其最大路径和。

本题中,路径被定义为一条从树中任意节点出发,达到任意节点的序列。该路径至少包含一个节点,且不一定经过根节点。

示例 1:

输入: [1,2,3]

       1
      / \
     2   3

输出: 6

示例 2:

输入: [-10,9,20,null,null,15,7]

   -10
   / \
  9  20
    /  \
   15   7

输出: 42

3、代码思路

核心思路:如果一个节点对路径的贡献值是负数,很明显,我们就并不需要这个节点,我们只要贡献值为正数的节点


假设有如下二叉树

image-20200723130633070


如何想要知道当前节点对路径的贡献值,首先就需要知道其左右子节点对路径的贡献值,所以我们需要先递归至二叉树的最深层,然后从最深层开始回溯

由于是左递归优先执行,所以我们先递归至左侧最深处的叶子节点 9

叶子节点 9 没有左右节点,所以其左右节点对路径的贡献值为 0 ,即对于节点 9 来说,其 leftGain = 0rightGain = 0

于是,回溯至节点 9 ,节点 9 路径的贡献值 = 节点 9 本身的贡献值 + max(节点 9 左节点的贡献值, 节点 9 右节点的贡献值) = 9 + 0 = 9 ,此时路径最大值暂时等于 9

此时最大的路径值 = 节点 9 本身的贡献值 + 节点 9 左节点的贡献值 + 节点 9 右节点的贡献值 = 9 + 0 + 0 = 9

image-20200723130641228


此时开始往二叉树的右边开始递归,递归至叶子节点 -10 ,该节点对路径的贡献值为 -10 ,不考虑,对于叶子节点 -6 也是同样的道理

image-20200723130701130


回溯至节点 15 ,其左右子节点的贡献值被当成 0 计算(因为贡献值为负数,还不如不走),路径长度为 15,比之前的 9 大,所以路径最大值暂时等于 15

节点 15 对路径的贡献值 = 节点 15 本身的贡献值 + max(节点 15 左节点的贡献值, 节点 15 右节点的贡献值) = 15 + 0 = 15

image-20200903122947818


执行完左递归后,执行右递归,节点 7 的左右子节点的贡献值分别为 89

image-20200723130720559


此时回溯至节点 7

如果抛去上一层节点不看,按照 8 --> 7 --> 9 的走法,路径长度为 8 + 7 + 9 = 24 ,比之前的 15 大,所以路径最大值暂时等于 24

如果节点 7 作为上层节点的中间节点,左右子节点只能选择一个,那么选择 7--> 9 的走法,路径值为 7 + 9 = 16 ,则是节点 7 对上层节点的路径最大贡献值

image-20200723131020479


此时回溯至节点 20

如果抛去上一层节点不看,按照 15 --> 20 --> 7 --> 9 的走法,路径长度为 15 + 20 + 7 + 9 = 51,比之前的 24 大,所以路径最大值暂时等于 51

如果节点 20 作为上层节点的中间节点,左右子节点只能选择一个,那么选择 20 --> 7--> 9 的走法,路径值为 20 + 7 + 9 = 36 ,则是节点 20 对上层节点的路径最大贡献值

image-20200723131108925


此时回溯值根节点 -10 ,根节点对路径的贡献值为负数,当做 0 处理

image-20200723131545359

4、代码实现

代码

/**
 * @ClassName MaxPathSumDemo
 * @Description TODO
 * @Author Heygo
 * @Date 2020/9/3 12:07
 * @Version 1.0
 */
public class MaxPathSumDemo {

    public static void main(String[] args) {

        TreeNode node1 = new TreeNode(-10);
        TreeNode node2 = new TreeNode(9);
        TreeNode node3 = new TreeNode(20);
        TreeNode node4 = new TreeNode(15);
        TreeNode node5 = new TreeNode(7);
        TreeNode node6 = new TreeNode(-10);
        TreeNode node7 = new TreeNode(-6);
        TreeNode node8 = new TreeNode(8);
        TreeNode node9 = new TreeNode(9);

        // 构造二叉树
        node1.left = node2;
        node1.right = node3;
        node3.left = node4;
        node3.right = node5;
        node4.left = node6;
        node4.right = node7;
        node5.left = node8;
        node5.right = node9;

        int maxGain = maxPathSum(node1);
        System.out.println(maxGain);
    }

    static int maxSum = Integer.MIN_VALUE;

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

    public static 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 priceNewpath = node.val + leftGain + rightGain;

        // 更新答案
        maxSum = Math.max(maxSum, priceNewpath);

        // 返回节点的最大贡献值
        return node.val + Math.max(leftGain, rightGain);
    }

    public static class TreeNode {
        int val;
        TreeNode left;
        TreeNode right;

        TreeNode(int x) {
            val = x;
        }
    }

}
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值