算法设计与分析(二)——最大子段和问题

问题描述:给定由n个整数组成的序列a1,a2,…an,试着找出一个连续字段和,使得该子段和值最大。
例如:-1,11,-4,13,-5,-2的最大字段和为20(11,-4,13)

枚举法:

假如将序列的所有值存储在数组当中,枚举思想就是依次遍历数组,确定目标字段的起点下表i,再从该起点到数组末尾确定终止下表j,计算出从起点i到终点j的累加和,找出最大值为止,代码如下,时间复杂度为n的平方数量级。

int Maxsum_1(int*a,int n)
{  int i,j,sum; 
   int max=0;
   for(i=0;i<n;i++){//起点下标
       sum=0;
     for(j=i;j<n;j++){//终点下标
       sum+=a[j];//起点不变,终点后移累加
       if(sum>max) max=sum;
     }
   }
   return(max);
}
分治法:
  • 分治基本思想:将难以分析解决的大问题,分解成较小规模的相同的子问题,分而治之,再利用子问题的解求出原问题的解。
  • 分治思想的典型应用:最大子段和问题。
  • 最大子段和的分治思想:将数组a[1…n]分解成a[1…n/2]和a[n/2+1…n]两部分,
    则a[1…n]最大子段和出现三种情况:

1.a[1…n]最大子段和出现在a[0…n/2-1]中
2.a[1…n]最大子段和出现在a[n/2…n-1]中
3.a[1…n]最大子段和为包括a[n/2]的中间部分,a[i]+a[i+1]+…a[j], i<=n/2, n/2+1<=j<n。

代码如下,时间复杂度O(nlogn).

int Maxsum_2(int*a,int begin,int end){//分治 :将大问题分成几个独立的小问题 
 int sum=0,lsum,rsum,s1=0,s2=0;
 int i,left=0,right=0;
 int mid=(begin+end)/2;//只有一个元素情况
 if(begin==end) sum=(a[begin]>0)?a[begin]:0;
 else{
  lsum=Maxsum_2(a,begin,mid);//第一种情况 左半区间最大子段和 
  rsum=Maxsum_2(a,mid+1,end);//第二种情况 右半区间最大子段和 
  //第三种情况 
  for(i=mid;i>=begin;i--){//以中位元素为起点向右遍历,找部分最大子段
   left+=a[i];
   if(left>s1) s1=left;
  }
  for(i=mid+1;i<=end;i++){//以中位元素为起点向左遍历,找部分最大子段
   right+=a[i];
   if(right>s2) s2=right;
  }
  //找出三种情况的最大值
  sum=s1+s2;
  if(sum<lsum) sum=lsum;
  if(sum<rsum) sum=rsum;
 }
 return sum;
} 
后言

作者小白会不断更新,发布一些自己所学习过程中的所思所想,其中会涉及到经典编程题,java或c++语言的知识总结,希望对正在阅读的你会有所帮助与启发,也欢迎大佬们评论指出错误和提出意见哦,一起进步吧。

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值