[数字技巧]最大连续子序列和
2013-09-09 12:48 庸男勿扰 阅读(384) 评论(0) 编辑 收藏 举报最大连续子序列和这个问题是一个比较常见的问题,出现在很多公司的面试笔试中。题目大概是这样描述的:
输入一个整形数组,数组中有正数也有负数,数组中连续一个或多个组成一个子序列,每个子序列都有一个和,求所有子序列的和的最大值。
一、暴力枚举
最暴力的解法是枚举起点和终点(或长度),连同求和的那个步骤,共三个for循环,复杂度是O(n3)。代码示例如下:
1 #include <cstdio> 2 #include <cstdlib> 3 #include <limits.h> 4 5 using namespace std; 6 7 int n; 8 int arr[1001]; 9 long maxRes; 10 int start; 11 int end; 12 long solve1(int *arr,int n) 13 { 14 long max = INT_MIN; 15 for(int i=0; i<n; i++){ 16 for(int j=i; j<n; j++){ 17 long total = 0; 18 for(int k=i; k<=j; k++) 19 total += arr[k]; 20 if(total>max) 21 max = total; 22 } 23 } 24 return max; 25 } 26 int main() 27 { 28 freopen("maxSub.in","r",stdin); 29 freopen("maxSub.out","w",stdout); 30 31 while(scanf("%d",&n)!=EOF && n>0){ 32 for(int i=0; i<n; i++){ 33 scanf("%d",&arr[i]); 34 } 35 maxRes = solve1(arr,n); 36 printf("%ld\n",maxRes); 37 } 38 return 0; 39 }
max表示从a[i]到a[j]的和。
二、暴力枚举的改进
显然这样的算法是非常丑陋的,是否存在可优化的地方呢?一个最明显的冗余计算便是:arr[0]+arr[1]+...+arr[i]被计算了n-i-1次。实际上,第三个求和的过程是多余的,我们在枚举终点的过程中,即可进行求和运算,每加一个新数,即与最大值比较。这种做法可以省掉一个for循环,时间复杂度降到了O(n2),代码如下:
1 int solve2(int *arr,int n) 2 { 3 long max = INT_MIN; 4 for(int i=0; i<n; i++){ 5 long total = 0; 6 for(int j=i; j<n; j++){ 7 total += arr[j]; 8 if(total>max) 9 max = total; 10 } 11 } 12 return max; 13 }
三、巧妙的解法
在做优化之前,我们应该有三个认识:
1、以上的都枚举了起点和终点,而题目中只关心最大和,是不是可以优化。
2、假设arr[i]是负数,那么最大子序列肯定不是以arr[i]为起点,因为以arr[i+1]为起点的子序列和肯定不会比以a[i]小。
3、假设arr[i]...arr[j]的和是负数,那么最大子序列完全可以从arr[j+1]开始,原因同上。
有了以上想法,我们不难写出以下代码:
1 int solve3(int *arr,int n) 2 { 3 long max = 0; 4 long total = 0; 5 for(int i=0; i<n; i++){ 6 total += arr[i]; 7 if(total > max) 8 max = total; 9 else if(total < 0) 10 total = 0; 11 } 12 return max; 13 }
这是一个线性时间常量空间的算法,最大的特点是一旦读入arr[i]就被立即处理,不再被记忆,这就是所谓的联机算法。
四、巧妙解法的两个改进
改进一、这种算法在数组中所有的数为负数时,是得不到正确结果的,通过对负数单独讨论,满足全负数情形;
改进二、在计算的过程中忽略了起始位置和终点位置,可通过做两次标记,保存起点和终点位置。
这里直接给出一道类似的题目,具体不在赘述。
http://www.cnblogs.com/codershell/p/3307795.html
出处:http://www.cnblogs.com/codershell
本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
如果您觉得对您有帮助,不要忘了推荐一下哦~