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
.
If you have figured out the O(n) solution, try coding another solution using the divide and conquer approach, which is more subtle.
假设A(0, i)区间存在k,使得[k, i]区间是以i结尾区间的最大值, 定义为Max[i], 在这里,当求取Max[i+1]时,
Max[i+1] = Max[i] + A[i+1], if (Max[i] + A[i+1] >0)
= 0, if(Max[i]+A[i+1] <0),如果和小于零,A[i+1]必为负数,没必要保留,舍弃掉
然后从左往右扫描,求取Max数字的最大值即为所求。
1 public int maxSubArray(int[] A) { 2 // Start typing your Java solution below 3 // DO NOT write main() function 4 int result = Integer.MIN_VALUE; 5 int curSum = 0; 6 for(int i = 0; i < A.length; i++){ 7 curSum += A[i]; 8 if(curSum > result){ 9 result = curSum; 10 } 11 if(curSum < 0){ 12 curSum = 0; 13 } 14 } 15 16 return result; 17 }
(2) Divide and Conquer
二分法:将数组分成左右两部分,递归求两部分最大连续子数组,由于最大连续子数组可能横跨左右,故需对这种情况进行处理
假设数组A[left, right]存在最大值区间[i, j](i>=left & j<=right),以mid = (left + right)/2 分界,无非以下三种情况:
subarray A[i,..j] is
(1) Entirely in A[low,mid-1]
(2) Entirely in A[mid+1,high]
(3) Across mid
对于(1) and (2),直接递归求解即可,对于(3),则需要以min为中心,向左及向右扫描求最大值,意味着在A[left, Mid]区间中找出A[i..mid], 而在A[mid+1, right]中找出A[mid+1..j],两者加和即为(3)的解。
比较三种情况下得到的子数组和,取其中最大值
1 public int maxSubArray(int[] A) { 2 // Start typing your Java solution below 3 // DO NOT write main() function 4 int max = Integer.MIN_VALUE; 5 return maxArray(A, 0, A.length - 1, max); 6 } 7 8 int maxArray(int[] A, int left, int right, int max){ 9 if(left > right){ 10 return Integer.MIN_VALUE; 11 } 12 13 int mid = (left + right) / 2; 14 int leftMax = maxArray(A, left, mid - 1, max); 15 int rightMax = maxArray(A, mid + 1, right, max); 16 17 max = Math.max(max, leftMax); 18 max = Math.max(max, rightMax); 19 20 int sum = 0, mlmax = 0; 21 for(int i = mid - 1; i >= left; i--){ 22 sum += A[i]; 23 if(sum > mlmax){ 24 mlmax = sum; 25 } 26 } 27 sum = 0; int mrmax = 0; 28 for(int i = mid + 1; i <= right; i++){ 29 sum += A[i]; 30 if(sum > mrmax){ 31 mrmax = sum; 32 } 33 } 34 max = Math.max(max, A[mid] + mlmax + mrmax); 35 return max; 36 }
时间复杂度: T(N) = 2*T(N/2) + O(N) 由主定理得 O(NlogN)