本文参考《数据结构(中国大学MOOC)》 from 浙江大学
问题描述:
给定N个整数的序列,求函数
的最大值。
算法1
穷举,把所有可能的情况都遍历一遍,找到最大值。程序如下:
int MaxSubseqSum1(int A[],int N)
{
int ThisSum,MaxSum=0;
int i,j,k;
for(i=0;i<N;i++){ /*i是子列左端位置*/
for(j=i;j<N;j++){ /*j是子列右端位置*/
ThisSum=0; /*ThisSum是从A[i]到A[j]的子列和*/
for(k=i;k<=j;k++)
ThisSum+=A[k];
if(ThisSum>MaxSum) /*如果刚得到的子列和更大*/
MaxSum=ThisSum; /*更新最大和*/
} /*j循环结束*/
} /*i循环结束*/
return MaxSum;
}
该方法一共有3层循环,其时间复杂度为
算法2
在第一个方法上的改进,只用了两个嵌套for循环。
int MaxSubseqSum2(int A[],int N)
{
int ThisSum,MaxSum=0;
int i,j;
for(i=0;i<N;i++){
ThisSum=0;
for(j=i;j<N;j++){
ThisSum+=A[j];
/*对于相同的i,不同的j,只要在上一次循环(当前j-1)的基础上累加1项(当前A[j])即可*/
if(ThisSum>MaxSum)
MaxSum=ThisSum;
}
}
return MaxSum;
}
该方法一共有2层循环,其时间复杂度为
算法3:分而治之
算法描述:通过递归不断划分数列,然后取最大值。
int Max3(int A,int B,int C)
{
return A>B?A>C?A:C:B>C?B:C;
}
int DivideAndConquer(int List[],int left,int right)
{ /*分治法求List[left]到List[right]的最大子列和*/
int MaxLeftSum,MaxRightSum; /*存放左右子列的解*/
int MaxLeftBorderSum,MaxRightBorderSum; /*存放跨分界线的结果*/
int LeftBorderSum,RightBorderSum;
int center,i;
if(left==right){ /*递归的终止条件,子列只有1个数字*/
if(List[left]>0) return List[left];
else return 0;
}
/*下面是“分”的过程*/
center=(left+right)/2; /*找到中分点*/
/*递归求得两边子列的最大和*/
MaxLeftSum=DivideAndConquer(List,left,center);
MaxRightSum=DivideAndConquer(List, center+1, right);
/*下面求跨分界线的最大子列和*/
MaxLeftBorderSum=0;
LeftBorderSum=0;
for(i=center;i>=left;i--){ /*从中线向左扫描*/
LeftBorderSum+=List[i];
if(LeftBorderSum>MaxLeftBorderSum)
MaxLeftBorderSum=LeftBorderSum;
}/*左边扫描结束*/
MaxRightBorderSum=0;
RightBorderSum=0;
for(i=center+1;i<=right;i++){/*从中线向右扫描*/
RightBorderSum+=List[i];
if(RightBorderSum>MaxRightBorderSum)
MaxRightBorderSum=RightBorderSum;
}/*右边扫描结束*/
/*下面返回“治”的结果*/
return Max3(MaxLeftSum,MaxRightSum,MaxLeftBorderSum+MaxRightBorderSum);
}
int MaxSubseqSum3(int List[],int N)
{/*保持与前两种算法相同的函数接口*/
return DivideAndConquer(List, 0, N-1);
}
该算法时间复杂度为
算法4:在线处理
算法描述:“在线”是指每输入一个数据就进行即时处理,在任何一个地方中止输入,算法都能正确给出当前解。
该算法从树列头向尾部累积,如果当前累加和为正,则继续累积可以使和变大,保留之;当前累加和为负时,继续累
积会让数值变小,就抛弃之。
int MaxSubseqSum4(int A[],int N)
{
int ThisSum,Maxsum;
int i;
ThisSum=Maxsum=0;
for(i=0;i<N;i++){
ThisSum+=A[i]; /*向右累加*/
if(ThisSum>Maxsum) /*发现更大和则更新当前结果*/
Maxsum=ThisSum;
else if(ThisSum<0) /*若当前子列和为负,抛弃之*/
ThisSum=0;
}
return Maxsum;
}
该算法时间复杂度为
运行结果对比
下图展示了以上四种算法的运行时间
总结
1.前三种算法都是将所有的子列遍历一遍,然后比较所有子列和得出最大值,只是采用的遍历方法不同,算法复杂度不同;
2.一个思路:当遇到时间复杂度为的算法时,我们要思考一下,看能不能将其时间复杂度降到