package Level3; import java.util.Arrays; /** * * 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. click to show more practice. More practice: If you have figured out the O(n) solution, try coding another solution using the divide and conquer approach, which is more subtle. * */ public class S53 { public static void main(String[] args) { int[] A = {1,2,-1,-2,2,1,-2,1,4,-5,4}; System.out.println(maxSubArray(A)); } // 一维DP,可省略掉dp数组 public static int maxSubArray(int[] A) { int max = A[0]; int[] sum = new int[A.length]; sum[0] = A[0]; for(int i=1; i<A.length; i++){ // 要么不用前面的结果,要么用,求两者较大的 sum[i] = Math.max(A[i], sum[i-1]+A[i]); max = Math.max(max, sum[i]); } // System.out.println(Arrays.toString(sum)); return max; } }
memory优化版,不用数组存了!
public class Solution { public int maxSubArray(int[] A) { int max = A[0]; int maxEndHere = A[0]; for(int i=1; i<A.length; i++){ maxEndHere = Math.max(A[i], maxEndHere+A[i]); max = Math.max(max, maxEndHere); } return max; } }
Divide & Conquer
// http://www.geeksforgeeks.org/largest-sum-contiguous-subarray/ public class MaximumSubarray { public static void main(String[] args) { // int[] a = {-2,-3,4,-1,-2,1,5,-3}; // int[] a = {-2,-3,-4,-1,-2,-1,-5,-3}; int[] a = {-2, -5, 6, -2, -3, 1, 5, -6}; System.out.println(maxSubArraySum2(a)); System.out.println(maxSubArraySumDC(a, 0, a.length-1)); } public static int maxSubArraySum(int[] a){ int maxSoFar = 0, maxEndingHere = 0; int _maxStartIndexSoFar_ = -1; int _maxStartIndexEndingHere_ = -1; int _maxEndIndexSoFar_ = -1; for(int i=0; i<a.length; i++){ if(maxEndingHere < 0){ maxEndingHere = 0; }else{ if(maxEndingHere == 0){ _maxStartIndexEndingHere_ = i; } maxEndingHere += a[i]; } if(maxEndingHere > maxSoFar){ maxSoFar = maxEndingHere; _maxEndIndexSoFar_ = i; _maxStartIndexSoFar_ = _maxStartIndexEndingHere_; } } System.out.println("range: " + _maxStartIndexSoFar_ + " , " + _maxEndIndexSoFar_); return maxSoFar; } // Handling negative public static int maxSubArraySum2(int[] a){ int maxSoFar = a[0], maxEndingHere = a[0]; for(int i=1; i<a.length; i++){ maxEndingHere= Math.max(a[i], maxEndingHere+a[i]); maxSoFar = Math.max(maxSoFar, maxEndingHere); } return maxSoFar; } // Divide and Conquerer O(nlogn) // http://www.geeksforgeeks.org/divide-and-conquer-maximum-sum-subarray/ public static int maxSubArraySumDC(int[] a, int l, int h){ if(l == h){ return a[l]; } // Find the mid point int m = (l+h)/2; return Math.max(Math.max(maxSubArraySumDC(a, l, m), maxSubArraySumDC(a, m+1, h)), maxCrossingSum(a, l, m, h)); } private static int maxCrossingSum(int[] a, int l, int m, int h) { int sum = 0; int leftSum = Integer.MIN_VALUE; for(int i=m; i>=l; i--){ sum += a[i]; if(sum > leftSum){ leftSum = sum; } } sum = 0; int rightSum = Integer.MIN_VALUE; for(int i=m+1; i<=h; i++){ sum += a[i]; if(sum > rightSum){ rightSum = sum; } } return leftSum + rightSum; } // Leetcode when to buy stock }
每个元素都可以选择用前面的curSum(如果是正数)或是不用(curSum为负)
public class Solution { public int maxSubArray(int[] A) { int len = A.length; if(len == 0){ return 0; } int curSum = A[0]; int maxSum = A[0]; for(int i=1; i<len; i++){ if(curSum < 0){ curSum = A[i]; }else{ curSum += A[i]; } maxSum = Math.max(maxSum, curSum); } return maxSum; } }