题目:给定整数(可能有负数),求
的最大值(为方便起见,如果所有整数均为负数,则最大子序列和为0)。
例:输入-2,11,-4,13,-5,-2时,答案为20。
分析:这个问题之所以有吸引力,主要是因为存在求解它的很多算法,而这些算法的性能又差异很大。该问题源于《数据结构与算法分析--C语言描述》第二章“算法分析”,该问题是算法分析入门的经典例子。有4种典型的算法,它们的时间复杂度分别是、
、
和
。
1、
int MaxSubsequenceSum (const int A[], int N)
{
int ThisSum, MaxSum, i, j, k;
MaxSum = 0;/*1*/
for (i = 0; i < N; i++)/*2*/
for (j = i; j < N; j++)/*3*/
{
ThisSum = 0;/*4*/
for (k = i; k <= j; k++)/*5*/
ThisSum += A[k];/*6*/
if (ThisSum > MaxSum)/*7*/
MaxSum = ThisSum;/*8*/
}
return MaxSum;/*9*/
}
运行时间为
![](https://i-blog.csdnimg.cn/blog_migrate/741a581146c302f1da4902df94d92afb.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/11e1e8cc4fba006f547d211f5f43ab01.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/9341d9048ac485106d2b2ee8de14876f.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/9341d9048ac485106d2b2ee8de14876f.gif-i)
![](https://i-blog.csdnimg.cn/blog_migrate/9341d9048ac485106d2b2ee8de14876f.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/c3299754e928ea2f481fa5683c77c997.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/9341d9048ac485106d2b2ee8de14876f.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/70025f271821157b0b679a090298fdf6.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/11e1e8cc4fba006f547d211f5f43ab01.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/ed02f60e6521237455669d0ab5a4da2a.gif)
2、
我们可以通过撤出一个for循环来避免立方运行时间。算法1中第5行和第6行上的计算过分地耗时了,改进后的算法时间复杂度为。
int MaxSubsequenceSum (const int A[], int N)
{
int ThisSum, MaxSum, i, j;
MaxSum = 0;/*1*/
for (i = 0; i < N; i++)/*2*/
{
ThisSum = 0;/*3*/
for (j = i;j < N; j++)/*4*/
{
ThisSum += A[j];/*5*/
if (ThisSum > MaxSum)/*6*/
MaxSum = ThisSum;/*7*/
}
}
return MaxSum;/*8*/
}
3、
分治策略:最大子序列和可能在三处出现。或者整个出现在输入数据的左半部,或者整个出现在右半部,或者跨越输入数据的中部从而占据左右两个部分。前两种情况可以递归求解。第三种情况的最大和可以通过求出前半部分的最大和(包含前半部分的最后一个元素)以及后半部分的最大和(包含后半部分的第一个元素)而得到。然后将这两个和加在一起。算法如下:
static int MaxSubSum (const int A[], int Left, int Right)
{
int MaxLeftSum, MaxRightSum;
int MaxLeftBorderSum, MaxRightBorderSum;
int LeftBorderSum, RightBorderSum;
int Center, i;
if (Left == Right)/*1*/
if (A[Left] > 0)/*2*/
return A[Left];/*3*/
else
return 0;/*4*/
Center = (Left + Right) / 2;/*5*/
MaxLeftSum = MaxSubSum(A, Left, Center);/*6*/
MaxRightSum = MaxSubSum(A, Center + 1, Right);/*7*/
MaxLeftBorderSum = 0; LeftBorderSum = 0;/*8*/
for (i = Center; i >= Left; i--)/*9*/
{
LeftBorderSum += A[i];/*10*/
if (LeftBorderSum > MaxLeftBorderSum)/*11*/
MaxLeftBorderSum = LeftBorderSum;/*12*/
}
MaxRightBorderSum = 0; RightBorderSum = 0;/*13*/
for (i = Center + 1; i <= Right ; i++)/*14*/
{
RightBorderSum += A[i];/*15*/
if (RightBorderSum > MaxRightBorderSum)/*16*/
MaxRightBorderSum = RightBorderSum;/*17*/
}
return Max3(MaxLeftSum, MaxRightSum, MaxLeftBorderSum + MaxRightBorderSum);/*18*/
}
int MaxSubsequenceSum(const int A[], int N)
{
return MaxSubSum(A, 0, N - 1);
}
令
![](https://i-blog.csdnimg.cn/blog_migrate/fbfc5fba3bed69eec5ff2de47781a64e.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/9341d9048ac485106d2b2ee8de14876f.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/9341d9048ac485106d2b2ee8de14876f.gif%3D1)
![](https://i-blog.csdnimg.cn/blog_migrate/2153268ff21dd40a8b9024c479522894.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/075a46aa2927a8f0368be6f6a3b765b6.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/21cb54cd3015471546fe9b9e44a64998.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/896d330d9398f8a51bab0111faf1b6e5.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/896d330d9398f8a51bab0111faf1b6e5.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/9341d9048ac485106d2b2ee8de14876f.gif/2)
![](https://i-blog.csdnimg.cn/blog_migrate/9341d9048ac485106d2b2ee8de14876f.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/1333c85d1cb2ddb0874a6e6be23d846e.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/89cbe12bf158f05cee2c6662f1fd0465.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/89cbe12bf158f05cee2c6662f1fd0465.gif+O%5Cleft%20%28%20N%20%5Cright%20%29)
![](https://i-blog.csdnimg.cn/blog_migrate/9341d9048ac485106d2b2ee8de14876f.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/896d330d9398f8a51bab0111faf1b6e5.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/ddc676ca69420a256dd1334fa3769492.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/2153268ff21dd40a8b9024c479522894.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6474b09341c92da8e0c7a2cb3f988271.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/267bfe0c95811ea878e72492894afc64.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/36132fb88120c41c445339f6302dcbfa.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/874cba370ef7a0509f69570e8cb20f83.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/9341d9048ac485106d2b2ee8de14876f.gif%3D2%5E%7Bk%7D)
![](https://i-blog.csdnimg.cn/blog_migrate/fbfc5fba3bed69eec5ff2de47781a64e.gif%3DN*%5Cleft%20%28%20k+1%20%5Cright%20%29%3DNlogN+N%3DO%5Cleft%20%28%20NlogN%20%5Cright%20%29)
4、
int MaxSubsequenceSum(const int A[], int N)
{
int ThisSum, MaxSum, j;
ThisSum = MaxSum = 0;/*1*/
for (j = 0; j < N; j++)/*2*/
{
ThisSum += A[j];/*3*/
if (ThisSum > MaxSum)/*4*/
MaxSum = ThisSum;/*5*/
else if (ThisSum < 0)/*6*/
ThisSum = 0;/*7*/
}
return MaxSum;/*8*/
}
该算法叫做联机算法(online algorithm),其特点是, 在任意时刻,算法都能对它已经读入的数据给出子序列问题的答案。仅需要常量空间并以线性时间运行的联机算法几乎是完美的算法!