问题描述:
给定N个整数的序列{A1,A2,A3,…An},求最大连续子列和
算法一
方法描述:暴力搜索,穷举 i 到 j 的所有可能子列和(0<= i <= j <= n),取其最大值。
时间复杂度:O(n^3)
C++实现
int MaxSubSum(int a[], int N){
int thisMax = 0, maxSum = -1;
for(int i = 0; i < N; i++){
for(int j = i + 1; j < N; j++){
thisMax = 0;
for(int k = i; k <= j; k++){
thisMax += a[k];
}
if(thisMax > maxSum)
maxSum = thisMax;
}
}
return maxSum;
}
算法二
算法描述:暴力搜索。穷举时在thisSum计数基础上直接加上a[j],不必每次都从 i 加到 j 。
时间复杂度:O(n^2)
C++实现
int MaxSubSum(int a[], int N){
int thisMax = 0, maxSum = -1;
for(int i = 0; i < N; i++){
thisMax = 0;
for(int j = i ; j < N; j++){
thisMax += a[j];
if(thisMax > maxSum)
maxSum = thisMax;
}
}
return maxSum;
}
算法三
算法描述:分治法。
- 将数列从中分成两个子数列,则最大子列有三种可能:在左边的数列中;在右边的数列中;一部分在左边数列,一部分在右边数列。
- 将左右两个子列不断二分,直至能直接判断当前数列的最大子列和,即子列元素个数小于等于 1 。如图:
时间复杂度:O(n * lg n)
Java实现
class Solution {
public int maxSub(int[] nums, int s, int e){
if(s >= e)
return nums[e];
int mid = (s+e)/2;
int leftMax = nums[mid], rightMax = nums[mid+1];
int leftSum = 0, rightSum = 0;
for(int i = mid; i >= s; i--){
leftSum += nums[i];
leftMax = Math.max(leftMax, leftSum);
}
for(int i = mid+1; i <= e; i++){
rightSum += nums[i];
rightMax = Math.max(rightMax, rightSum);
}
leftMax = Math.max(0, leftMax);
rightMax = Math.max(0, rightMax);
int max = Math.max(maxSub(nums, s, mid), maxSub(nums, mid+1, e));
if(max < 0)
return max;
return Math.max(max, leftMax+rightMax);
}
//调用
public int maxSubArray(int[] nums) {
return maxSub(nums, 0, nums.length-1);
}
}
算法4
算法描述:在线处理。从数列第一个元素开始处理,依次向后求和,若发现当前所得的数列元素和为负,则舍弃之前所有元素,重新计数。
时间复杂度:O(n)
C++实现
int MaxSubSum(int a[], int N){
int thisMax = 0, maxSum = -1;
for(int i = 0; i < N; i++){
thisMax += a[i];
if(thisMax < 0)
thisMax = 0;
else if(thisMax > maxSum)
maxSum = thisMax;
}
return maxSum;
}