Leetcode - Maximum Subarray


My code:

public class Solution {
public int maxSubArray(int[] nums) {
if (nums == null || nums.length == 0)
return 0;
else if (nums.length == 1)
return nums[0];

    int maxSum = nums[0];
    int currSum = nums[0];
    for (int i = 1; i < nums.length; i++) {
        currSum = currSum >= 0 ? currSum + nums[i] : nums[i]; 
        maxSum = Integer.max(maxSum, currSum);  
    }
    return maxSum;
}

}


My test result:

![](http://upload-images.jianshu.io/upload_images/161212-fd9cf6a95e234da4.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)


这道题目不算很难,但我知道我一定会想复杂。所以在动手痛苦得设置状态机之前还是决定看下别人的思路吧。否则又是乱写,浪费时间。靠if语句做出答案。思维是垃圾的。
其实面对这种,求 max of sub array 的题目,我每次一看到题,都会一种误解,需要求出这个最大值,方法是,找出求得这个最大值的区域范围。
其实完全不需要。我们只需要求最大值。那么,最大值可以不断刷新,当新的更大的值出现的时候,就将maxSum刷新。而不需要记录这个刷新值的起点和尾点是哪里。
于是只需要考虑一种情况。
当 currSum < 0 时,此时后一个值加上 currSum ,总sum都会变小。
所以直接将 currSum = nums[i]
如果 nums[i] <= 0 , 那么,也许,原 currSum 是要大于 此时的currSum的。
但那又如何呢?currSum保存的只是现在的和。而最大和,是保存在 maxSum里面的。
所以只需要比较下原maxSum 和 现currSum 大小即可。取最大值。
如果 nums[i] > 0, 那么此刻,因为 currSum <= 0 ,所以
currSum + nums[i] <= nums[i] 的。所以可以从nums[i] 重新开始,不需要加上之前的负数。
如果原currSum > 0 ,那就直接加上 nums[i], 不断与maxSum比较,不断刷新maxSum即可。

**
总结: Array, DP。 求 sub array 的最大和。记住,只需要求出最大和,而不需要考虑任何有关该最大和起止点的问题。
** 

Anyway, Good luck, Richardo!



My code:

public class Solution {
public int maxSubArray(int[] nums) {
if (nums == null || nums.length == 0)
return 0;
int tracker = nums[0];
int max = nums[0];
for (int i = 1; i < nums.length; i++) {
tracker = Math.max(tracker + nums[i], nums[i]);
max = Math.max(max, tracker);
}
return max;
}
}


刚做完 maximum subarray product, 
http://www.jianshu.com/p/e1456b90c819
所以这道题做起来比较快。

差不多的思路,用一个tracker去追踪之前最大的和,必须与现在这个index相连。然后,再综合找出最大值。

Anyway, Good luck, Richardo!


一开始也是直接拿O(n) 方法做的,后来看到有 divide and conquer做法,就看了解释,然后自己写了一遍。

```java
public class Solution {
    public int maxSubArray(int[] nums) {
        if (nums == null || nums.length == 0) {
            return 0;
        }
        
        return helper(nums, 0, nums.length - 1);
    }
    
    private int helper(int[] nums, int left, int right) {
        if (left == right) {
            return nums[left];
        }
        int middle = left + (right - left) / 2;
        int leftMax = helper(nums, left, middle);
        int rightMax = helper(nums, middle + 1, right);
        int leftPart = Integer.MIN_VALUE;
        int temp = 0;
        for (int i = middle; i >= left; i--) {
            temp += nums[i];
            leftPart = Math.max(leftPart, temp);
        }
        int rightPart = Integer.MIN_VALUE;
        temp = 0;
        for (int i = middle + 1; i <= right; i++) {
            temp += nums[i];
            rightPart = Math.max(rightPart, temp);
        }
        
        int crossMax = leftPart + rightPart;
        return Math.max(crossMax, Math.max(leftMax, rightMax));
    }
}

参考:
https://discuss.leetcode.com/topic/49641/simple-divide-and-conquer-solution-java-answer-for-the-more-practice

只不过觉得好没意思。。。太不自然的想法了,速度也很慢。

Anyway, Good luck, Richardo!

如果问,找出这个sub array 的途径:

My code:

public int[] maxSubArrayPath(int[] nums) {
    if (nums == null || nums.length == 0) {
        return null;
    }
    
    int max = nums[0];
    int sum = nums[0];
    int begin = 0;
    int end = 0;
    int currBegin = 0;
    int currEnd = 0;
    for (int i = 1; i < nums.length; i++) {
        if (sum + nums[i] >= nums[i]) {
            sum += nums[i];
            currEnd = i;
        }
        else {
            sum = nums[i];
            currBegin = i;
            currEnd = i;
        }
        if (max < sum) {
            begin = currBegin;
            end = currEnd;
            max = sum;
        }
    }
    return new int[]{begin, end};
}

如果问,找出不大于 k 的最大sub array 和
My code:

public int maxSubArrayK(int[] nums, int k) {
        int n = nums.length;
        int[] sums = new int[n];
        int temp = 0;
        TreeSet<Integer> set = new TreeSet<Integer>();
        for (int i = 0; i < nums.length; i++) {
            temp += nums[i];
            sums[i] = temp;
            set.add(temp);
        }
        set.add(0);
        int max = Integer.MIN_VALUE;
        for (int i = 0; i < nums.length; i++) {
            Integer num = set.ceiling(nums[i] - k);
            if (num != null) {
                max = Math.max(max, nums[i] - num);
            }
        }
        
        return max == Integer.MIN_VALUE ? -1 : max;
    }

Anyway, Good luck, Richardo! — 09/24/2016

    原文作者:Richardo92
    原文地址: https://www.jianshu.com/p/ac172786c4ab#comments
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞