您的位置:首页 > 其它

寻找最大连续子串和

2013-05-20 14:38 274 查看
《编程之美》上的一个经典问题,拿来练习一下

给定一整型数组a[0...n],找出连续子串a[x...y],使得和最大,其中,0<=x<=y<=n。

方法很多,采用动态规划的方法可以达到线性O(n)的时间复杂度。

动态规划需要满足无后效性,分析这个问题,考察数组a[0...m](m<n)的最大连续子串和,有三种可能的情况。

第一:最大的连续子串中不包含a[m],则result[0...m]=result[0...m-1],和前m-1个元素的最大子串和相同。
第二:由包含a[m-1]的前m-1个元素的最大子串和,加上a[m]组成。
第三:由a[m]自己单独组成

假定以a[i]结尾的和最大子串为L[i],那么
L[i]=MAX{a[i],a[i]+L[i]};
result[0...i]=MAX{L[i],max[0...i-1]},即取这三者之中的最大值,满足无后效性。

我们可以定义两个长度为n的数组,一个L[i]用来存储前i个元素中包含a[i]的最大子串和,一个result[i]用来存储前i个元素整体的最大子串和。初始化L[i]=result[i]=a[0],之后从1开始遍历整个数组,采用上面的递推式计算两个数组的值,最后求得result
就是所要的结果。

上述过程还可以进一步简化,因为注意到每次计算L[i],result[i]的时候,实际上只用到了上一步的结果L[i-1],result[i-1],实际上我们不需要存储整个数组,只需存储两个中间变量即可,这样可以把问题的空间复杂度降低到常数级。

上面过程只求出了最大子串和,如果需要最大子串的位置,再引入几个辅助变量,记录其左、右边界,在每次更新result和l的时候,更新它们即可。具体见下面代码(这里把上面所述的记录L的变量记为cur)

#include<stdio.h>

int main(){
int a[]={0,-2,3,5,-1,2};
int n=6;

int result=a[0];
int cur=a[0];
int subl=0,subr=0,tempsubl=0;
for(int i=0;i<n;i++){
if(cur>0)
cur+=a[i];
else{
cur=a[i];
tempsubl=i;
}
if(cur>result){
result=cur;
subr=i;
subl=tempsubl;
}
}
printf("max=%d\n",result);
printf("from a[%d] to a[%d]\n",subl,subr);
return 0;
}


下面是几个测试用例

输入
a[]={0,-2,3,5,-1,2};
结果
max=9
from a[2] to a[5]

输入
a[]={1,-2,3,5,-3,2};
结果
max=8
from a[2] to a[3]

输入(输入全为负数的情况也可以正常运行)
a[]={-9,-2,-3,-5,-3,-4};
结果
max=-2
from a[1] to a[1]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: