最大子序列和的问题是这样的:Given a sequence S of integer, find the largest sum of a consecutive subsequece of S.(0, if all negative items). 例如,对于序列-2,11,-4,13,-5,-2来说,其最大子序列和是20:(11,-4,13)。
这个问题很简单,但是通过解答这道题可以看出一个人的算法修养有多深。下面详细介绍一下这个问题算法设计的四个层次:O(n^3)->O(n^2)->O(nlgn)->O(n). 为了方便描述,所以使用了伪代码。
第一层次:也就是一种brute-force算法,其复杂度为O(n^3),即考虑所有的情况:
MaxSum = 0;
for (i = 0; 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;
第二层次:也比较容易想到,其复杂度为O(n^2):
MaxSum = 0;
for (i = 0; i < N; i++)
{
ThisSum = 0;
for (j = i; j < N; j++)
{
ThisSum += A[j];
if (ThisSum > MaxSum)
MaxSum = ThisSum;
}
}
return MaxSum;
第三层次:使用Divide-and-Conquer法,其复杂度为O(nlgn),要考虑三种情况:
Center = (Left + Right) / 2;
MaxLeftSum = MaxSubSum(A, Left, Center); MaxRightSum = MaxSubSum(A, Center + 1, Right);
MaxLeftBorderSum = 0; LeftBorderSum = 0;
for (i = Center; i >= Left; i--)
{
LeftBorderSum += A[i];
if (LeftBorderSum > MaxLeftBorderSum) MaxLeftBorderSum = LeftBorderSum;
}
MaxRightBorderSum = 0; RightBorderSum = 0;
for (i = Center + 1; i <= Right; i++)
{
RightBorderSum += A[i];
if (RightBorderSum > MaxRightBorderSum) MaxRightBorderSum = RightBorderSum;
}
return Max3(MaxLeftSum, MaxRightSum, MaxLeftBorderSum + MaxRightBorderSum);
第四层次:这也是最优算法,用反证法很容易证明,其复杂度为O(n),操作示意如下:
注:第一排记录ThisSum的变化,第二排记录MaxSum的变化,第三排就是给出的序列。
ThisSum = MaxSum = 0;
for (j = 0; j < N; j++)
{
ThisSum += A[j];
if (ThisSum > MaxSum)
MaxSum = ThisSum;
else if (ThisSum < 0)
ThisSum = 0;
}
return MaxSum;
一斑而可窥全豹,只要一个算法还没有证明是最优的都可以改进,但是对于上面的线性算法来说已是最优的了,可以不必再改了。