今天我们讨论的最大子列和问题出自陈越老师主编的《数据结构(第二版)》
在这篇文章中我们即将讨论最大子列和问题的解。
通过不同的算法,我们将看到算法不同时算法效率的巨大效率,从而对算法的复杂度分析有更深刻的理解。
【问题描述】
给定n个整数的序列{a1,a2,a3,···,an},求函数最大值。
【问题分析】
关于上述问题,我们可以将“子列”理解维一串连续的数字,这里想要求得的最大值即为从这串数字某一个数字个体出发加到某一个数字个体截止的所有数字之和。在求的过程中不断更新最大值,返回所有最大值中最大的那个,值得注意的是,当最后的最大值为负数时,我们要取0为最终答案。在这个过程中,我们在程序测试阶段将给定示例序列:{-2,11,-4,13,-5,-2},其最大子列为{11,-4,13},和为20。
【算法】
【算法一】
最直接的方法就是穷举所有的子列和,从中找出最大值。
与此同时,最内层的k循环涉及大量重复计算,代码效率低下。
int MaxSubseqSuml(int List[], int N)
{
int i, j, k;
int ThisSum, MaxSum = 0;
for(i=0; i<N;i++){ //i是子列左端位置
for(j=i; j<N; j++){ //j是子列右端位置
ThisSum=0; //List[i]到List[j]的子列和
for(k=i; k<=j; k++)
ThisSum+=List[k];
if(ThisSum>MaxSum)
MaxSum=ThisSum; //更新
return MaxSum;
}
【算法二】
部分存储中间值大的穷举,当然,这仍不是最快的算法。
int MaxSubseqSum2(int List[], int N)
{
int i, j;
int ThisSum, MaxSum = 0;
for(i=0; i<N;i++){ //i是子列左端位置
ThisSum=0; //List[i]到List[j]的子列和
for(j=i; j<N; j++){ //j是子列右端位置
ThisSum+=List[j];
if(ThisSum>MaxSum)
MaxSum=ThisSum; //更新
return MaxSum;
}
【算法三】
分而治之,个人觉得这里可以说是来自二分查找中得到的灵感。
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)
{
int MaxLeftSum,MaxRightSum;
int MaxLeftBorderSum, MaxRightBorderSum;
int LeftBorderSum, RightBorderSum;
int center,i;
if(left==right){
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;
MaxRightBBorderSum=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);
}
下一篇文章将讲解在线处理算法,记得关注哦!