LeetCode------Binary Tree Maximum Path Sum

这里写图片描述

求二叉树的最大路径和是一道蛮有难度的题,难就难在起始位置和结束位置可以为任意位置,我当然是又不会了,于是上网看看大神们的解法,像这种类似数的遍历的题,一般来说都需要用DFS来求解,我们先来看一个简单的例子:
这里写图片描述
由于这是一个很简单的例子,我们很容易就能找到最长路径为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中较大的那个值,而不是两个都要,参见代码如下:

public class solution{
    public int maxPathSum(TreeNode root) {
        max_sum = Integer.MIN_VALUE;
        //错误写法:如果定义递归时直接把max_sum当做参数传递进去则结果一直是Integer.MIN_VALUE.
        //因为Java是值传递,dfs拿到的是max_sum的副本,对它进行修改并不会影响到全局的max_sum.
        //dfs(root,max_sum);
        dfs(root);
        return max_sum;
    } 
    //维护一个全局变量max_sum,且没有把它当做参数直接传进去,在dfs方法中对max_sum的修改和赋值会直接影响到max_sum的值
    private int max_sum;

    private int dfs(TreeNode root) {
        if (root == null) return 0;
        int l = dfs(root.left);
        int r = dfs(root.right);
        int sum = root.val;
        if (l > 0) sum += l;
        if (r > 0) sum += r;
        max_sum = Math.max(max_sum, sum);
        return Math.max(r, l) > 0 ? Math.max(r, l) + root.val : root.val;
    }
}

我们应该尽量避免使用全局变量,所以这里其实可以用一个ArrayList对象来代替全局变量,代码如下:

public int maxPathSum(TreeNode root) {
    if(root==null)
        return 0;
    //维护一个ArrayList(避免使用全局变量),但其实只用到第一个位置
    ArrayList<Integer> res = new ArrayList<Integer>();
    res.add(Integer.MIN_VALUE);
    helper(root,res);
    return res.get(0);
}
private int helper(TreeNode root, ArrayList<Integer> res)
{
    if(root == null)
        return 0;
    int left = helper(root.left, res);
    int right = helper(root.right, res);
    int cur = root.val + (left>0?left:0)+(right>0?right:0);
    if(cur>res.get(0))
        res.set(0,cur);
    return root.val+Math.max(left, Math.max(right,0));
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值