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
.
最优解法:
//O(N)的算法,思想有点类似于双pointer
//sum为数组前i项和,如果sum为正,那么就留着,如果为负,那么就舍弃,从第i+1项再尝试取subarray累计和
//如此只需要从前向后一次遍历即可
public class Solution {
public static int maxSubArray(int[] A) {
int maxSum = Integer.MIN_VALUE;
int sum = 0;
for(int i=0; i<A.length; i++){
sum += A[i];
if(sum > maxSum)
maxSum = sum;
if(sum < 0) //当前subarray的前i项和为负,舍弃前i项,重新累计求和
sum = 0;
}
return maxSum;
}
}
分治与递归:
//Divide and Conquer: 算法复杂度为O(NlogN)
//最大和的subarray有三种可能:即subarray完全位于A的左半部、subarray完全位于A的右半部,或subarray跨越A的中分线
//第三种情况时,subarray必然包含A左的最后一个元素及A右的第一个元素
//将三种情况分别求解,取大者返回
public class Solution {
private int maxSumDAC(int[] array, int left, int right){
if(left == right) return array[left];
int center = (left+right)/2;
int maxLeftSum = maxSumDAC(array, left, center); //分治与递归
int maxRightSum = maxSumDAC(array, center+1, right);
int maxLeftBorderSum = Integer.MIN_VALUE;
int leftBorderSum = 0;
for(int i=center; i>=left; i--){
leftBorderSum += array[i];
if(leftBorderSum > maxLeftBorderSum) maxLeftBorderSum=leftBorderSum;
}
int maxRightBorderSum = Integer.MIN_VALUE;
int rightBorderSum = 0;
for(int i=center+1; i<=right; i++){
rightBorderSum += array[i];
if(rightBorderSum > maxRightBorderSum) maxRightBorderSum=rightBorderSum;
}
if(maxLeftSum>=maxRightSum) //三者取大返回
return Math.max(maxLeftSum, maxLeftBorderSum+maxRightBorderSum);
else
return Math.max(maxRightSum, maxLeftBorderSum+maxRightBorderSum);
}
public int maxSubArray(int[] A) {
return maxSumDAC(A, 0, A.length-1);
}
}
两种遍历方法:
public class Solution {
public int maxSubArray(int[] A) {
int maxSum = Integer.MIN_VALUE;
for(int i=0; i<A.length; i++) //通过三重循环,穷举所有可能子数组的和
for(int j=i; j<A.length; j++){
int sum = 0;
for(int k=i; k<=j; k++){ //取i-j内的subarray求和
sum += A[k];
}
if(sum > maxSum) maxSum = sum;
} //算法为O(N3),提示超时
return maxSum;
}
}
public class Solution {
public int maxSubArray(int[] A) {
int maxSum = Integer.MIN_VALUE;
for(int i=0; i<A.length; i++){ //算法为O(N2),提示超时
int sum = 0;
for(int j=i; j<A.length; j++){ //在内循环内,计算i-j的子数组的和
sum += A[j];
if(sum > maxSum) maxSum = sum;
}
//if(sum > maxSum) maxSum = sum; //注意:判断语句不能放在此处
} //因为在内循环内,每一个j就求了一个子数组和
//如果if放到外面,就相当于整个数组A求和,再与maxSum比了
return maxSum;
}
}