问题:给定N个整数序列,{A1,A2,…,An},求该序列中存在的最大的连续n个整数和。
分析:
方法1:最自然的方法是设置子列和的左端索引i和右端索引j,然后通过遍历的方法找出最大的子列和,其中最简单的数组求和也是遍历相加,因此将会有三层循环,计算复杂度为O(N^3)
代码为:
int MaxSum1(int a[],int N){//暴力求解,复杂度O(N^3)
int i=0;
int j=0;
int k=0;
int MaxSum=0;
int sum=0;
for(i=0;i<N;i++)
{
for(j=i;j<N;j++)
{
for(k=i;k<=j;k++)
{
sum+=a[k];
if (MaxSum<sum) MaxSum=sum;
}
sum=0;
}
}
return MaxSum;
}方法2:注意到在求子列和时,是依次推移进行的,因此可以讲方法1中的求和循环,修改为依次叠加,前索引1次迭代完成后要做一次清0;计算复杂度下降为O(N^2);
int MaxSum2(int a[],int N){//优化,复杂度O(N^2)
int i=0,j=0,Sum=0,MaxSum;
for(i=0;i<N;i++){
for(j=i;j<N;j++){
Sum=Sum+a[j];
if(MaxSum<Sum) MaxSum=Sum;
}
Sum=0;
}
return MaxSum;
}方法3:分而治之
将数据一分为2,最大子列和会有三种情况:在左边,在右边,中间线往两边。前两者可以才有递归实现,中间往两边可以另外考察。最后返回这三个数据中最大的一项;计算复杂度为NlogN
int Max3(int A,int B,int C){
// return A>B?A>C?A:C:B>C?B:C;
return A > B ? A > C ? A : C : B > C ? B : C;
}
int MaxSum3(int a[],int left,int right){
int MaxSumLeft=0,MaxSumRight=0;
int i;
int MaxBroLeft=0,MaxBroRight;
int BroLeftSum=0,BroRightSum=0;
int MaxBro;
int center=(left+right)/2;//中间位置
if (left==right)//迭代停止条件
{
if (a[left]>0) return a[left];
else return 0;
}
MaxSumLeft=MaxSum3(a,left,center);//左最大子列和
MaxSumRight=MaxSum3(a,center+1,right);//右最大子列和
//向左搜索
for (i=center;i>=left;i--)
{
BroLeftSum+=a[i];
if (MaxBroLeft<BroLeftSum)
MaxBroLeft=BroLeftSum;
}
//向右搜索
for (i=center;i<=right;i++)
{
BroRightSum+=a[i];
if (MaxBroRight<BroRightSum)
MaxBroRight=BroRightSum;
}
MaxBro=MaxBroRight+MaxBroLeft-a[center];
return (Max3(MaxBro,MaxSumLeft,MaxSumRight));
}方法4:在线处理
我们想象数据流依次进入系统,每进入一个数据,就做一次分析,分析发现,若新进入的数据,使得最大和边为负数,则该数不可能作为一个新子列的前索引,同时上一索引点结束,只保留上一状态的最大子列和,之后再对后续进入的数据分析。
计算复杂度为O(N)
int MaxSum4(int a[],int N){//在线,计算复杂度O(N)
int i=0;
int Sum=0,MaxSum=0;
for (i=0;i<N;i++)
{
Sum+=a[i];
if (MaxSum<Sum)
MaxSum=Sum;
if (Sum<0) Sum=0;
}
return MaxSum;
} 主函数:
int main(int argc, char *argv[]) {
int a[8]={4,-3,5,-2,-1,2,6,-2};
int Max=0;
int N=8;
Max=MaxSum4(a,N);
//Max=MaxSum3(a,0,N-1);
printf("MaxSum:%d",Max);
return 0;
}
本文探讨了四种不同方法来解决最大连续子序列和的问题,包括暴力求解、优化求和、分治策略及在线处理,详细介绍了每种方法的实现思路与复杂度。

2969

被折叠的 条评论
为什么被折叠?



