Maximum Subarray LT53

Given an integer array nums, find the contiguous subarray (containing at least one number) which has the largest sum and return its sum.

Example:

Input: [-2,1,-3,4,-1,2,1,-5,4],
Output: 6
Explanation: [4,-1,2,1] has the largest sum = 6.

Follow up:

If you have figured out the O(n) solution, try coding another solution using the divide and conquer approach, which is more subtle.

Idea 1: For all pairs of integers i and j satisfying 0 <= i  <= j < nums.length, check whether the sum of nums[i..j] is greater than the maximum sum so far, take advange of:

  sum of nums[i..j] = sum of nums[i..j-1] + nums[j]

the sum of all continuous subarray starting at i can be calculated in O(n), hence we have a quadratic algorithm.

Time complexity: O(n2)

Space complexity: O(1)

class Solution {
    public int maxSubArray(int[] nums) {
        int sz = nums.length;
        int maxSumSoFar = Integer.MIN_VALUE;
        
        for(int i = 0; i < sz; ++i) {
            int sumStartHere = 0;
            for(int j = i; j < sz; ++j) {
                sumStartHere += nums[j];
                maxSumSoFar = Math.max(maxSumSoFar, sumStartHere);
            }
        }
        return maxSumSoFar;
    }
}

Idea 1.a:  With the help of a cumulative sum array, cumarr[0...i], which can be computed in linear time,  it allows the sum to be computed quickly,

sum[i..j] = cumarr[j] - cumarr[i-1].

Time complexity: O(n2)

Space complexity: O(n)

class Solution {
    public int maxSubArray(int[] nums) {
        if(nums == null || nums.length < 1) return 0;
       int sz = nums.length;
        int[] cumuSum = new int[sz];
        
        cumuSum[0] = nums[0];
        for(int i = 1; i < sz; ++i) {
            cumuSum[i] = cumuSum[i-1] + nums[i]; 
        }
        
        int maxSumSoFar = Integer.MIN_VALUE;
        for(int i = 0; i < sz; ++i) {
            for(int j = i; j < sz; ++j) {
                int previousSum = 0;
                if(i > 0) {
                    previousSum = cumuSum[i-1];
                }
                maxSumSoFar = Math.max(maxSumSoFar, cumuSum[j] - previousSum);
            }
        }
        
        return maxSumSoFar;
    }
}

 

class Solution {
    public int maxSubArray(int[] nums) {
        if(nums == null || nums.length < 1) return 0;
       int sz = nums.length;
        int[] cumuSum = new int[sz];
        
        cumuSum[0] = nums[0];
        for(int i = 1; i < sz; ++i) {
            cumuSum[i] = cumuSum[i-1] + nums[i]; 
        }
        
        int maxSumSoFar = Integer.MIN_VALUE;
        for(int j = 0; j < sz; ++j) {
            maxSumSoFar = Math.max(maxSumSoFar, cumuSum[j]);
            for(int i = 1; i <= j; ++i) {
                maxSumSoFar = Math.max(maxSumSoFar, cumuSum[j] - cumuSum[i-1]);
            }
        }
        
        return maxSumSoFar;
    }
}

Idea 2: divide and conquer. Divide into two subproblems, recusively find the maximum in subvectors(max[i..k], max[k..j]) and find the maximum of crossing subvectors(max[i..k..j]), return the max of max[i..k], max[k..j] and max[i..k..j].

 Time complexity: O(nlgn)

Space complexity: O(lgn) the stack

class Solution {
    private int maxSubArrayHelper(int[] nums, int l, int u) {
        if(l >= u) return Integer.MIN_VALUE;
        int mid = l + (u - l)/2;
        
        int leftMaxSum = nums[mid];
        int sum = 0;
        for(int left = mid; left >=l; --left) {
            sum += nums[left];
            leftMaxSum = Math.max(leftMaxSum, sum); 
        }
        
        int rightMaxSum = 0;
        sum = 0;
        for(int right = mid+1; right < u; ++right) {
            sum += nums[right];
            rightMaxSum = Math.max(rightMaxSum, sum);
        }
        
        return Math.max(leftMaxSum + rightMaxSum, 
                       Math.max(maxSubArrayHelper(nums, l, mid), maxSubArrayHelper(nums, mid+1, u)));
    }
    
    public int maxSubArray(int[] nums) {
        return maxSubArrayHelper(nums, 0, nums.length);
    }
}

Idea 3: Extend the solution to the next element in the array. How can we extend a solution for nums[0...i-1] to nums[0..i].

The key is the max sum ended in each element, if extending to the next element, 

maxHere(i) = Math.max( maxHere(i-1) + nums[i], nums[i])

maxSoFar = Math.max(maxSoFar, maxHere)

Time compleixty: O(n)

Space complexity: O(1)

class Solution {   
    public int maxSubArray(int[] nums) {    
        int maxHere = 0;
        int maxSoFar = Integer.MIN_VALUE;
        
        for(int num: nums) {
            maxHere = Math.max(maxHere, 0) + num;
            maxSoFar = Math.max(maxSoFar, maxHere);
        }
        
        return maxSoFar;
    }
}

Idea 3.a: Use the cumulative sum,

maxHere = cumuSum(i) - minCumuSum

cumuSum(i) = cumuSum(i-1) + nums[i]

maxSoFar = Math.max(maxSoFar, maxHere) = Math.max(maxSoFar, cumuSum - minCumuSum)

Time compleixty: O(n)

Space complexity: O(1)

class Solution {   
    public int maxSubArray(int[] nums) {    
        int min = 0;
        int cumuSum = 0;
        int maxSoFar = Integer.MIN_VALUE;
        
        for(int num: nums) {
            cumuSum += num;
            maxSoFar = Math.max(maxSoFar, cumuSum - min);
            min = Math.min(min, cumuSum);
        }
        
        return maxSoFar;
    }
}

 

posted on 2019-02-17 00:20  一直走在路上  阅读(153)  评论(0编辑  收藏  举报

导航