最大连续子数列和一道很经典的算法问题,给定一个数列,其中可能有正数也可能有负数,我们的任务是找出其中连续的一个子数列(不允许空序列),使它们的和尽可能大。我们一起用多种方式,逐步优化解决这个问题。
例:
输入{ -2, 11, -4, 13, -5, -2 }时,答案为 20 (从A2到 A4).
算法1:
#include <stdio.h>
//N是数组长度,A是待计算的数组,放在全局区是因为可以开很大的数组
int N, A[1024];
int MaxSumsequenceSum(const int A[],int N);
int main()
{
//输入数据
scanf("%d", &N);
for(int i = 1; i <= N; i++)
scanf("%d", &A[i]);
printf("%d\n",MaxSumsequenceSum(A,N));
return 0;
}
int MaxSumsequenceSum(const int A[],int N)
{
int ThisSum,MaxSum,i,j,k;
MaxSum=0;
for( i = 1; i <= N; i++)
for( j = i; j <= N; j++)
{
ThisSum = 0;
for( k = i; k <= j; k++)
ThisSum+=A[k];
if(ThisSum>MaxSum)
MaxSum=ThisSum;
}
return MaxSum;
}
算法2:
int MaxSumsequenceSum(const int A[],int N)
{
int ThisSum,MaxSum,i,j;
MaxSum=0;
for( i = 1; i <= N; i++)
{
ThisSum=0;
for( j = i; j <= N; j++)
{
ThisSum+=A[j];
if(ThisSum>MaxSum)
MaxSum=ThisSum;
}
return MaxSum;
}
算法3:
static int MaxSubSum(int A[], int left, int right){
int maxLeftSum, maxRightSum;
int maxLeftBorderSum, maxRightBorderSum;
int leftBorderSum, rightBorderSum;
if(left == right)
if(A[left] > 0)
return A[left];
else
return 0;
int mid = (left + right) / 2, i;
maxLeftSum = MaxSubSum(A, left, mid);
maxRightSum = MaxSubSum(A, mid + 1, right);
maxLeftBorderSum = 0, leftBorderSum = 0;
for(i = mid; i >= left; i--){
leftBorderSum += A[i];
if(leftBorderSum > maxLeftBorderSum)
maxLeftBorderSum = leftBorderSum;
}
maxRightBorderSum = 0, rightBorderSum = 0;
for(i = mid + 1; i <= right; i++){
rightBorderSum += A[i];
if(rightBorderSum > maxRightBorderSum)
maxRightBorderSum = rightBorderSum;
}
return max3(maxLeftSum, maxRightSum, maxLeftBorderSum + maxRightBorderSum);
}
算法4:
int MaxSumsequenceSum(const int A[],int N)
{
int ThisSum,MaxSum , j ;
ThisSum=MaxSum=0;
for( j = i; j <= N; j++)
{
ThisSum+=A[j];
if(ThisSum>MaxSum)
MaxSum=ThisSum;
else if(ThisSum<0)
ThisSum=0;
}
return MaxSum;
}
四种算法的复杂度分别为O(N^3), O(N^2) , O(NlogN) , O( N);
其中算法3采用的是”分治(divide-and-conquer)策略. 其想法是把问题分成两个大致相等的子问题,然后递归的对他们求解,这是”分”部分,”治”阶段将两个子问题的解合并到一起并可能在做些少量的附加工作,最后的到问题的解;
算法4的一个附带优点是:它只对数据进行一次扫描,一旦A[i]被读入并处理,它就不再被记忆。因此,如果数组在磁盘上,它就可以被顺序读入,在主存中不必存储数组的任何部分。不仅如此,在任意时刻,算法都能对它已经读出子序列问题的正确答案(其他算法不具有这个特性), 具有这种特性的算法叫做联机算法( online algorithm),仅需要常量空间并以线性时间运行的联机算法几乎是完美的算法.