先说这道题最简单的方法,也就是二重循环不断判断就行,遇见更大的就换起点和终点,小技巧是,如果遍历的第一个数是负数就可以直接跳过此次循环开始下一次。
//二重循环一直判断
#include <stdio.h>
int main(void){
int N;
int a[100000];
int sum = -9999999;
int start = 0;
int end = 0;
scanf("%d", &N);
for(int i=0;i<N;i++){
scanf("%d", &a[i]);
}
for(int i=0;i<N;i++){
int temp = a[i];
if(temp < 0)
continue;
for(int j=i;j<N;j++){
if(j != i)
temp += a[j];
if(temp > sum){
sum = temp;
start = i;
end = j;
}
}
}
if(sum < 0){
printf("0 %d %d", a[0], a[N-1]);
return 0;
}
printf("%d %d %d", sum, a[start], a[end]);
return 0;
}
接下来的方法参考了https://blog.youkuaiyun.com/weixin_38097576/article/details/82715413中的方法,但这篇文章中的方法存在一个问题,即无法正确判断诸如:0 0 0 1 2 -9这样的输入,正确的输出应该是3 0 2,但用链接中的方法得出的答案是3 1 2,于是考虑在这种方法上改进,并写为C语言,代码修改后如下:
#include <stdio.h>
int val(int );
int main(void){
int N;
int a[100000];
int result;
int start = 0;
int end = 0;
int sum[100000];
int zero = 0;
scanf("%d", &N);
for(int i=0;i<N;i++){
scanf("%d", &a[i]);
}
sum[N-1] = val(a[N-1]);
result = sum[N-1];
for(int i=N-2;i>=0;i--){
sum[i] = val(a[i] + sum[i+1]);
if(sum[i] >= result){
result = sum[i];
start = i;
}
}
for (int i = 0; i < N; i++) {//判断如果sum全为0时,原数据中是否存在0
if (a[i] > 0)
break;
if(a[i] == 0){
zero++;
}
if (i == N - 1) {
if(zero > 0){
printf("0 0 0");
return 0;
}
else{
printf("0 %d %d", a[0], a[N-1]);
return 0;
}
}
}
for(int i=start+1; i<N;i++){
if(sum[i] == 0){
end = i-1;
break;
}
else if (i == N - 1) {
end = i;
}
}
printf("%d %d %d", result, a[start], a[end]);
return 0;
}
int val(int i){
if(i>0)
return i;
return 0;
}
改动的点为:链接中的算法,dp数组存储的是向前的最大和,改动后改为sum存储向后的最大和,改了之后就可以保证i和j是最小的。这种方式的时间复杂度要明显低于上一种,上一种时间复杂度为O(n^2),毕竟用了二重循环,这一种方法为O(n),空间上多了一个用于存储和的数组sum[],但时间性能更优,典型的空间换时间。