Leetcode Maximum SubArray & Binary Tree Maximum Path Sum

发现这两道题运用了同一个思路,把它们放到一起

Problem: Maximum SubArray 

Find the contiguous subarray within an array (containing at least one number) which has the largest sum.

For example, given the array [−2,1,−3,4,−1,2,1,−5,4],
the contiguous subarray [4,−1,2,1] has the largest sum = 6.

Solve the Problem on Leetcode

分析:

我们这么想,当我们从头到尾遍历这个数组的时候,对于一个数组里的数字,它有几种选择呢?

它只有两种选择: 1. 加入之前的SubArray, 2. 自己另起一个SubArray

好,那什么时候会出现这两种情况呢。

注意我们是找累加的最大值,那么,

如果之前SubArray的总体和大于0的话,我们可以认为其对后续数字是有贡献的。这种情况下我们选择加入之前的SubArray

如果之前SubArray的总体和为0或者小于0的话,我们可以认为其对后续数字是没有贡献,甚至是有害的(小于0时)。这种情况下我们只能选择以这个数字开始,另起一个SubArray

明白了这点,代码就很好写了, sum记录之前SubArray的和,max用来返回最大值,当sum的值大于max时,说明发现和更大的SubArray序列,此时更新max的值。

public class Solution {
    public int maxSubArray(int[] A) {
        int max = Integer.MIN_VALUE;
        int sum = 0;
        for(int i=0; i<A.length; i++){
            sum = sum>0? sum + A[i]: A[i];
            max = Math.max(sum,max);
        }
        return max;
    }
}

明白了这个题,再看Binary Tree Maximum Path Sum 就非常直观了


Problem: Binary Tree Maximum Path Sum

Given a binary tree, find the maximum path sum.

The path may start and end at any node in the tree.

For example:
Given the below binary tree,

       1
      / \
     2   3

Return 6.

Solve the Problem on Leetcode

分析:

首先,我们应该注意到这个Path能从任意节点开始,到任意节点结束,不过不要被它吓住,仔细想想是不是和上面的题差不多

如果说Array只有一个方向的话,那么Binary Tree其实只是左,右两个方向而已,我们需要比较两个方向上的值

那好,如果说Array可以从头到尾遍历,那么Binary Tree怎么办呢,我们可以采用Binary Tree最常用的dfs来进行遍历

我们先上代码:

public class Solution { 			//代码是MITBBS里面Peking2二爷的思路
    int max;
    public int maxPathSum(TreeNode root) {
        max = Integer.MIN_VALUE;
        dfs(root);
        return max;
    }
    
    public 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 = Math.max(max,sum);
        return Math.max(r,l)>0?Math.max(r,l)+root.val:root.val;
    }
}

我们结合代码和下面这个图来进行说明


首先,L, R 是dfs返回的两个子分支的值我们先不提。对于sum,我们照搬第一题的思路

如果L大于0,那么对后续是有利的,我们加上L。 例如图中A节点,左子树大于0,那么更新最大路径的和为【B, A】的和

如果R大于0,那么对后续是有利的,我们加上R。例如图中A节点,右子树大于0,那么更新最大路径的和为【C, A】的和

如果L,R同时大于0,左右两边对后续都是有利的,我们两边都要,例如图中A节点,左右子树都大于0,那么更新最大路径的和为【B,A,C】的和

如果L,R都小于等于0,那么左右两边对后续都是无利甚至有害的,我们从这个节点,另起一个路径,例如图中的A节点,更新最大路径的和0为【A】的和

好了,sum怎么来的我们已经很清楚了,还有一点值得注意是在Return的语句里

return Math.max(r,l)>0?Math.max(r,l)+root.val:root.val;

可能有人疑惑了,为什么只返回一个方向的值呢?(如果Math.max(r,l)>0, 我们只返回这两个方向上最大值的方向)

我们需要明确sum 和 return 返回值的区别,还是举A节点的例子

对于sum,当我们两个方向的值都取得时候,路径是图中绿色笔的路径,是因为分析sum的时候我们是站在A节点的角度上分析的

而对于Return,A节点最后Return的时候,是返回到上一层D节点的递归中。重点是,Return方向是向上的。所以不会出现图中绿色的路径,只可能出现红色的两个路径中的一条(当Math.max(l,r)>0时)或者就一个D节点(当Math.max(l,r)<=0时)

这一点明确后,整个题就变得很直观了,最后记得持续更新max,当发现更大路径和的时候

这两个题放到一起,大家感受一下。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值