题目:
分析:
思路一:
要求最大的子串和,最简单粗暴的方法就是枚举法,枚举出所有可能的子串并求和,然后逐一比较,得出和最大的子串,用两重循环就可以实现。比如 a[3]={1,-2,3},第一重循环i从0到2,第二重循环j从i+1到2,这样的话,就有以下的情况:
* 1 =1
* 1 -2 =-1
* 1 -2 3 =2
* -2 =-2
* -2 3 =1
* 3 =3
所以最大子串和就是3。
思路二:
思路一的方法可行,但是有些情况可以不用考虑,直接跳过,也就是说有些情况下第二重循环可以提前结束。这样的话可以节省一些时间。当某个时候,子串和是负数时,就可以直接跳出第二重循环了,由于对后面的情况,如果加上一个负数,就一定会比不加要小,所以后面不会是和最大的了。比如上面的例子,当出现1 -2时,和是-1,为负数,那么1 -2 3的情况就可以不考虑了,因为它的和一定会比最后一种情况3要小。同样的,出现-2后,-2 3的情况也可以不考虑,这样就可以简便一些。
思路三:
上面两种方法虽然可行,但都需要两重循环,思路二虽然跳过了一些情况,但还是过于复杂。这里提出第三种方法,如果理解了思路二的简化原理后,理解第三种方法就比较容易了。要求最大的子串和,可以用一个temp来进行累加,如果temp>=0,就把当前的数加入temp,当遇到temp<0时,就让temp等于当前的数。因为当temp>0时,对后面的子串来说,是使和增大,而当temp<0时,对后面的子串来说是使和减小,最大的子串和一定是出现在后面。比如a[5]={1,2,-4,5,6},temp=1,加上2就是3,对2来说是使子串和变大。temp=3,对-4来说,也是使-4变大,所以加上-4.temp=-1,对5来说是使5变小,所以不加,令temp=5,再加上6,就是最大的子串和。如果刚才加上temp=-1,对于5 6这个子串来说,他们的和就变小了。这样一来,就只需要遍历一遍就好了,一重循环就够了,大大降低了时间复杂度。
代码:
思路一:
#include<stdio.h>
int main()
{
int n,a[100000];
int i,j;
int max,temp; //max记录最大子串和,temp用于累加
scanf("%d",&n);
for(i=0;i<n;i++)
scanf("%d",&a[i]);
max=a[0];
for(i=0;i<n;i++)
{
temp=a[i];
if(temp>max) //如果temp>max,就用max记录
max=temp;
for(j=i+1;j<n;j++)
{
temp+=a[j];
if(temp>max)
max=temp;
}
}
printf("%d
",max);
return 0;
}
思路二:
#include<stdio.h>
int main()
{
int n,a[100000];
int i,j;
int max,temp; //max记录最大子串和,temp用于累加
scanf("%d",&n);
for(i=0;i<n;i++)
scanf("%d",&a[i]);
max=a[0];
for(i=0;i<n;i++)
{
temp=a[i];
if(temp>max) //如果temp>max,就用max记录
max=temp;
for(j=i+1;j<n;j++)
{
temp+=a[j];
if(temp<=0) //temp<0,提前结束循环
break;
if(temp>max)
max=temp;
}
}
printf("%d
",max);
return 0;
}
思路三:
#include<stdio.h>
int main()
{
int n,i,a[100000];
int temp=0;
int max=-1001;
scanf("%d",&n);
for(i=0;i<n;i++)
scanf("%d",&a[i]);
for(i=0;i<n;i++)
{
if(temp<0) //temp<0,等于当前数
temp=a[i];
else //temp>=0,temp继续累加
temp+=a[i];
if(temp>max) //如果temp>max,就用max记录
max=temp;
}
printf("%d
",max);
return 0;
}