最大连续子序列问题的研究
来源:互联网 发布:华北电力网络中心 楼 编辑:程序博客网 时间:2024/06/07 23:14
最大连续子序列,即从一个序列中选取一段连续的子序列,使这个子序列的和最大,例如0 6 -1 1 -6 7 -5 最大和为7,从第一个数到第6个数,最大子序列有动态规划法和分治法两种,首先讨论分治法,对一个序列而言,最大连续子序列要么在左边的序列中,要么在右边的序列中(从中间断开),要么在左右各一部分,显然,从这个角度想,我们将问题划分为了两个子问题,从左边找最大连续子序列或者从右边找连续子序列,如果在中间,那么我们只需要暴力遍历,左边从mid到left,右边从mid+1到right,
显然,T(n)=T(n/2)*2+n,其中n代表最坏情况下最大子序列在中间,而且从left到right,复杂度为O(nlog2n)以下是我实现的代码。
<span style="font-family:Courier New;">int *maxsum(int a[],int left,int right) { int *m=new int[3]; //m[0]记录最大连续子序列起始位置,m[1]记录终止位置,m[2]表示最大和 if(left==right) { // 返回条件 m[0]=m[1]=left; m[2]=a[left]; //cout<<m[0]<<" "<<m[1]<<" "<<m[2]<<endl; return m; } int mid=(left+right)/2; int *l=maxsum(a,left,mid); int *r=maxsum(a,mid+1,right); //左右递归,划分子问题 int leftsum=a[mid],maxleft=a[mid]; //暴力求解maxleft m[0]=mid; for(int i=mid-1;i>=left;i--) { leftsum+=a[i]; if(leftsum>=maxleft) { maxleft=leftsum; m[0]=i; } } int rightsum=a[mid+1],maxright=a[mid+1];</span><span style="font-family: 'Courier New';">//暴力求解maxright</span><span style="font-family:Courier New;"> m[1]=mid+1; for(int i=mid+2;i<=right;i++) { rightsum+=a[i]; if(rightsum>=maxright) { maxright=rightsum; m[1]=i; } } m[2]=maxleft+maxright; if(l[2]>=m[2] && l[2]>=r[2]) { //防止内存泄露,及时处理new的内存 delete m; delete r; //cout<<l[0]<<" "<<l[1]<<" "<<l[2]<<endl; return l; } else if(m[2]>=l[2] && m[2]>=r[2]) { delete l; delete r; //cout<<m[0]<<" "<<m[1]<<" "<<m[2]<<endl; return m; } else if(r[2]>=m[2] && r[2]>=l[2]) { delete m; delete l; //cout<<r[0]<<" "<<r[1]<<" "<<r[2]<<endl; return r; }}</span>
以下是杭电1003的分治法求解实现,使用上述函数
<span style="font-family:Courier New;">#include <cstdio>#include <cstring>#include <iostream>using namespace std;const int maxn=100000+5;int t[maxn];int *maxsum(int a[],int left,int right) { int *m=new int[3]; if(left==right) { m[0]=m[1]=left; m[2]=a[left]; //cout<<m[0]<<" "<<m[1]<<" "<<m[2]<<endl; return m; } int mid=(left+right)/2; int *l=maxsum(a,left,mid); int *r=maxsum(a,mid+1,right); int leftsum=a[mid],maxleft=a[mid]; m[0]=mid; for(int i=mid-1;i>=left;i--) { leftsum+=a[i]; if(leftsum>=maxleft) { maxleft=leftsum; m[0]=i; } } int rightsum=a[mid+1],maxright=a[mid+1]; m[1]=mid+1; for(int i=mid+2;i<=right;i++) { rightsum+=a[i]; if(rightsum>=maxright) { maxright=rightsum; m[1]=i; } } m[2]=maxleft+maxright; if(l[2]>=m[2] && l[2]>=r[2]) { delete m; delete r; //cout<<l[0]<<" "<<l[1]<<" "<<l[2]<<endl; return l; } else if(m[2]>=l[2] && m[2]>=r[2]) { delete l; delete r; //cout<<m[0]<<" "<<m[1]<<" "<<m[2]<<endl; return m; } else if(r[2]>=m[2] && r[2]>=l[2]) { delete m; delete l; //cout<<r[0]<<" "<<r[1]<<" "<<r[2]<<endl; return r; }}int main() { int T; cin>>T; for(int ca=1;ca<=T;ca++ ){ int n; cin>>n; for(int i=0;i<n;i++) { cin>>t[i]; } int *p=maxsum(t,0,n-1); cout<<"Case "<<ca<<":"<<endl; cout<<p[2]<<" "<<p[0]+1<<" "<<p[1]+1<<endl; delete p; if(ca<T) cout<<endl; } return 0;}</span>
2,尝试使用动态规划法求解,对我而言真的很不显然,以下标 i 结尾的序列的最大连续字段和 maxsum[i] = ( maxsum[i-1] , 0) +a[i] (其实就是判断前n-1个最大字段和是否大于0 ,如果大于,显然加上前面的,否则,要自己就够了) 显然复杂度为O(n),根据maxsum的值,暴力向前,暴力向后,也能找到起始和结束,以下是实现的代码,还是上面的一题hdu1003
<span style="font-family:Courier New;">#include <cstdio>#include <cstring>#include <cstdlib>#include <iostream>using namespace std;const int maxLen=100000+5;int a[maxLen];int maxn[maxLen];int main(){ int T; scanf("%d",&T); for(int time=1;time<=T;time++) { int n; scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); maxn[0]=-1005; for(int i=1;i<=n;i++) { maxn[i]=max(a[i],a[i]+maxn[i-1]); } int maxNum=-1005,End=0; for(int i=1;i<=n;i++) { if(maxn[i]>maxNum) { maxNum=maxn[i];End=i; } } printf("Case %d:\n%d",time,maxNum); int Begin; int sum=0; for(int i=End;i>=1;i--) { sum+=a[i]; if(sum==maxNum) Begin=i; } printf(" %d %d\n",Begin,End); if(time<T) printf("\n"); } return 0;}</span>
0 0
- 最大连续子序列问题的研究
- 最大连续子序列和的问题
- 最大连续子序列之和的问题
- 最大连续子序列问题
- 最大连续子序列问题
- [数据结构]连续子序列最大和,最大积的问题
- 轰炸问题、连续子序列的积、n个最大连续子序列和
- 求和最大的连续子序列问题分…
- 连续子序列最大和问题的分析
- 关于最大连续子序列问题的解法
- 最大连续子序列问题的java实现
- 连续子序列最大和问题的分析
- 总结java最大连续子序列和的问题
- 关于最大连续子序列问题
- 连续子序列最大和问题
- 1011 最大连续子序列问题
- 连续子序列和最大问题
- 最大连续子序列和 问题
- tomcat启动死循环
- jQuery $.post() 方法
- Unity3D研究院之IOS&Android收集Log文件(六十二)
- java的值传递,没有引用传递
- 第三周练习 最大公约数(多个数字)
- 最大连续子序列问题的研究
- Ubuntu删除了全部普通用户后怎么进入系统(linux中guest用户切换为root登陆)
- hdu1421 搬寝室--DP
- 原生AJAX实现异步请求
- Linux最大连接数问题
- vr的延迟和渲染效率优化与Nvidia VRWorks
- 029给变量赋值正确么?
- 第三周练习 太乐了
- iperf3打流