最大连续整数和

原文地址:最大连续整数和 作者:Seiyagoo
【题目描述】从一串随机的整数中找出连续的一段使得它们的和最大。(也可以不找任何整数,这时候和算 0)。例如: 4-532-1-35。和最大的连续一段为 32-1-32(和为 6

 

 

 

    【分析】面对这样的一道题目我们可以设计出很多种算法。先看看最一般的方法吧。把所有的连续段的和都算出来,再从中找一个最大的。我们设这些整数为a1a2、……、an。把第i个到第j个的和记为S[i][j]。用这种方法也就是找到所有的S[i][j]1<=i<=j<=n),而对于每一个S[i][j]需要遍历aiaj之间的整数,所以容易判断时间复杂度为O(n^3)。这个参考程序如下

 

 【参考程序1

 

 #include "stdio.h"

 

 

 

int main()

 

{

 

int a[1000];  //保存整数

 

int n;  //整数个数

 

int i , j , k;  //循环变量

 

int sum;  //

 

int max;  //最大的和,即本题的结果

 

 

 

         //读入数据

 

         scanf("%d" , &n);

 

         for (i = 0; i < n; i ++) scanf("%d" , &a[i]);

 

         max = 0;

 

         //3重循环,时间复杂度为O(n^3)

 

         for (i = 0; i < n; i ++)

 

                   for (j = i; j < n; j ++)

 

                   {

 

                            sum = 0;

 

                            for (k = i; k <= j; k ++) sum += a[k];

 

                            if (sum > max) max = sum;

 

                   }

 

         printf("%dn" , max);

 

         return 0;

 

}

 

    当然很容易想到一个改进的办法,因为S[i][j]=S[j]-S[i]。而S[i]我们可以用递推的方法求出,即S[i] = S[i-1] + a[i],这样就可以通过扫描一遍求出所有的S[i],然后再枚举所有的S[i][j],因为这2个操作没有嵌套,所以时间复杂度为O(n^2)

 

【参考程序2

 

#include "stdio.h"

 

 

 

int main()

 

{

 

int a[1000];  //保存整数

 

int n;  //整数个数

 

int i , j;  //循环变量

 

int sum[1000];  //sum[i]表示从第0个元素到第i个元素的和

 

int max;  //最大的和,即本题的结果

 

 

 

         //读入数据

 

         scanf("%d" , &n);

 

         for (i = 0; i < n; i ++) scanf("%d" , &a[i]);

 

         max = 0;

 

         //预处理,算出所有的S1i

 

         sum[0] = a[0];

 

         for (i = 1; i < n; i ++) sum[i] = sum[i-1] + a[i];

 

         //2重循环,时间复杂度为O(n^2)

 

         for (i = 0; i < n; i ++)

 

                   for (j = i; j < n; j ++)

 

                            if (sum[j]-sum[i] > max) max = sum[j]-sum[i];

 

         printf("%dn" , max);

 

         return 0;

 

}

 

    但是这还并不是这道题目的最简解答,下面看看这道题目最帅的算法吧。因为一个负数加上一个正数一定会使得正数变小。针对这一点,我们再把那一列整数分段来看,分成a1、……、ak,和a(k+1)1<=k),这样如果2段要联系起来,第一段中选的整数必须到最右端,即要包括ak,所以我们可以找出最大的Sik(1<=i<=k),记为Smax。如果Smax<0,则Smax0。这样再看看与a(k+1)的和是不是正数,如果是正数则保留这个和作为下一次的Smax,因为前段最大的值加上这个数,构成的一定是这一段的Smax。当然如果与a(k+1)的和小于0,就Smax0。每次对改变的Smax判断是否为最大值,这样就只要对数列遍历一遍即可求解。时间复杂度也就成了O(n),而且这种算法的实现也非常的简单。

 

【参考程序3

 

#include

 

 

 

int main()

 

{

 

int a[1000];  //保存整数

 

int n;  //整数个数

 

int i;  //循环变量

 

int sum;  //即为Smax

 

int max;  //最大的和,即本题的结果

 

 

 

         //读入数据

 

         scanf("%d" , &n);

 

         for (i = 0; i < n; i ++) scanf("%d" , &a[i]);

 

         max = 0; sum = 0;

 

    //一遍循环搞定,时间复杂度O(n)

 

         for (i = 0; i < n; i ++)

 

         {

 

                   sum += a[i];

 

                   if (sum < 0) sum = 0;

 

                   if (sum > max) max = sum;

 

         }

 

         printf("%dn" , max);

 

         return 0;

 

}

特例:对于全为负数,求最大值即可

其他解法参考:http://topic.csdn.net/u/20100929/09/b9c84138-b5d2-4cfa-bcd4-140ffedfbc11.html?71519

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值