最大子序列和的问题是这样的: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;
一斑而可窥全豹,只要一个算法还没有证明是最优的都可以改进,但是对于上面的线性算法来说已是最优的了,可以不必再改了。