day18 二叉树中的最大路径和

leetcode 124 二叉树中的最大路径和

在这里插入图片描述

没看懂题目什么意思,先从群里大佬那里偷来个思路研究研究
借鉴地

思路

对于二叉树的问题,可以将其抽象成一种简单的结构,即:

    根
   /    \
 左子树 右子树

对于这道题目同样如此,题目要求任意节点出发到达任意节点的最大路径和。根据上面抽象出来的结果,我们最多能够得到三条满足题意的路径:

  • 左子树最大路径和 + 根
  • 右子树最大路径和 + 根
  • 左子树 + 根 + 右子树
    这就是所有的路径了, 按照题目求出他们之间的最大值即是题目的结果。

不过需要注意的一点是,如果左右子树的最大路径和是负数,那么还不如不加他们呢。

对于第一种和第二种情况,都可以通过递归进行计算,但是第三种情况,我们是没办法进行递归的,所以在每次的方法体中,都要对其进行一次判断。

为什么不能划分出单独的左子树、右子树、根节点这样的路径呢?这是因为:

我们给出的树是一个抽象出来的树,它是递归的,实际上运行的时候我们可以通过后序遍历,会先计算出左右子树上最大路径和,单独的左右子树的可能在递归的时候已经被计算到了,所以就不需要再考虑

而对于根节点而言,如果左右子树的最大路径和不为负数,那当然要加它们了,必然比自己大,而如果左右子树的最大路径和为负数,那么就不会加它们,也就相当于单独的根节点了。

以上是大致思路。

代码

进入代码编写环节,首先要明确我们是要用递归来做这道题目的,然后就要进行递归三部曲。

  • 确定递归的参数与返回值
  • 确定递归体的内容
  • 确定递归的终止条件

递归的参数与返回值

是先要明确,我们的递归函数是要用来求子树+根节点的最大路径和,所以返回值应该是一个int类型的变量。而传入参数只需要一个root即可。

所以函数签名可以确定好了:int maxPath(TreeNode)

递归体的内容

我们在递归的时候要做什么呢?

首先要进行一个后序遍历,即求出左右子树的最大路径和,就需要递归的调用本函数。

int left = maxPath(root.left);

int right = maxPath(root.right);

left和right就是左右子树的最大路径和。

这个明确了以后就可以计算 根 + 左子树 和 根 + 右子树中的最大路径和了。

只不过有一点需要注意,当左右子树的值为负数的情况下,要舍弃掉它们。

int maxChildVal = root.val +Math.max(0, Math.max(left,right));

这个maxChildVal就是当前树的最大路径和,之后要返回的就是它。

接下来计算 根节点 + 左子树 + 右子树 的值,同样叶是如果左右子树最大路径和小于0就不加它们,相当于+0了

int rootVal = root.val + Math.max(0, Math.max(left,0)+ Math.max(right,0));

接下来要看究竟哪个值才是当前递归树的最大子树和了

就要进行一次比较

int max = Math.max(rootVal,maxChildVal)

max就是当前树下的最大路径和。不过这也只是局部的,它在局部最大并不代表在全局最大呀,此时就需要定义一个全局变量res,它可以保存全局的最大路径和。

res = Math.max(res,max)

比较之前记录好的最大路径和,与当前的最大路径和究竟谁大,然后保存大的那个。

最后比较结束,返回maxChildVal

递归终止条件

本题的终止条件很简单,就是递归到了最后的空结点。

if(root == null) retrun 0;

复杂度分析

时间复杂度:该算法将所有的结点都遍历到了,时间复杂度为O(n)

空间复杂度:我们需要一个大小与树等高的栈开销,因为要递归。所以空间复杂度为O(log(N))

下面是详细代码

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
    // 对于一棵树而言,它的最大路径和有三种可能。一颗无论多大的树可以看作是这样的抽象
    //    a 
    //    /\
    //   b  c
    // 可能是a + b + c
    // 可能是a + b + (a父节点)
    // 可能是a + b + (a父节点)
    // 对于 a + b + c 而言,它不能够被递归,已经是最终值了。
    // 对于 a + b 或 a + c 而言,它还有可能更大 因为a也可能有一个为正数的父节点,因此我们可以递归求最大的左右子树。
    // 对于a + b 、 a + c 、 a + b + c这三者,我们要比较一下究竟谁最大,最大者就是当前树的环境下的最大者。如果还有父节点就继续递归求解。
    // 不过可能会存在负值,加一个负值还不如不加,所以判断是否比0小,如果小这个值就取0。
    // 但是对于a点而言,它是不允许被舍弃的,因为无论那种情况下,都需要它作为联络点。
class Solution {
    int res = Integer.MIN_VALUE;
    // 求二叉树的最大路径和
    public int maxPathSum(TreeNode root) {
        
        maxPath(root);
        return res;
    }
    int maxPath(TreeNode root)
    {
        if(root == null)
        {
            return 0;
        }
        int left = maxPath(root.left);
        int right = maxPath(root.right);
        // 先求出要返回的子树值,即a + b 和 a + c两者最大值,当然,如果双方都小于0,那么就返回一个0表示路径不会包括这棵子树的节点。
        int maxChildVal = root.val +Math.max(0, Math.max(left,right));
        // 这是a + b + c 的值
        int rootVal = root.val  + Math.max(0, Math.max(left,0)+ Math.max(right,0));
        // 比较双方的大小,取大者与返回值比较。
        res = Math.max(res,Math.max(rootVal,maxChildVal));
        return maxChildVal;

    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值