RT,求一数组中元素的最大连续子段和。
方法一。
不考虑超时的影响,可以使用循环暴力解决,a[i][j]表示i是开头元素,j为结尾元素,需要使用三层循环,时间复杂度为0(n^3);
#include<iostream> using namespace std; int b[100][100]; int main() { int a[100]; int n,k; cin>>n; for(k=0;k<n;++k) cin>>a[k]; int i,j; for(i=0;i<n;++i) for(j=i;j<n;++j) for(k=i;k<=j;++k) { b[i][j]=b[i][j]+a[k]; } int max=-222; for(int s=0;s<n;++s) for(int B=0;B<n;++B) if(b[s][B]>max) max=b[s][B]; cout<<max<<endl; system("pause"); return 0; }
方法二。
方法一中的a[i][j],可以由Sum[j]-Sum[i-1]到,到使时间复杂度降为O(n^2),代码略~
方法三。时间复杂度O(n).
利用动态规划,由于我是看别人才理解此算法的,所以说说我的理解吧。
#include<iostream> using namespace std; int main() { int t; cin>>t; while(t--) { int n,a[100001]; memset(a,0,100001); cin>>n; for(int i=0;i<n;++i) cin>>a[i]; int temp=0,max=-32222,k=1; for(int j=0;j<n;++j) { temp=temp+a[j]; //子段之间的相加 if(temp>max) { max=temp; //保存最大值的信息 } if(temp<0) //舍弃之前的子段 { temp=0; } } cout<<max<<endl; } system("pause"); return 0; }
举个例子,a[4]={-11,-8,9,2}; 显然最大子段和是 9+2=11;
该代码从头到尾扫描一次,如果只有一项,则最大子段和是它本身,不管是否为负数还是正数。
假设第二项为正数的话,显然最大子段和就是第二项本身了,该怎样解决了呢,这样想,因为这是求连续子段和,倘若该项的前n-1项连续子段和为负数,则最大子段和max就会改变,因为一个数加上一个负数,值会减小。所以当前n-1项连续子段和为负数时,就舍弃这一段,从头开始。但注意,最大连续子段和中的元素可以允许有负数的存在,此时就需要设置一个max来保存最大值的情况,如果增加,则更新max的情况,否则不更新。