昨天看到一个算法题目,题目是这样子的:
输入一组整数,求出这组数字子序列和中最大值。也就是只要求出最大子序列的和,不必求出最大的那个序列。例如:
序列:-2 11 -4 13 -5 -2,则最大子序列和为20。
序列:-6 2 4 -7 5 3 2 -1 6 -9 10 -2,则最大子序列和为16。
这个题目也是在CSDN上看到的,个人觉得题目还是说明不够详细,比如当序列为:-1 -2 -3 时,则最大子序列和是-1 还是 0 呢?我看题目的楼主也并没有考虑到,默认序列中一定会出现正整数。从正常角度理解应该是 -1 ,这种情况后面的解法中,我将按照和为 -1 的理解,并且 求出最大子序列。我的思路是这样的:假设最大子序列 和为Max;
从两个方面考虑,
第一种情况 是序列中全是负数的特殊情况,这种情况,只要遍历找到最大的负数,即为最大子序列和,其中的负数也就是最大子序列的;
第二种是 排除第一种情况的一般情况:
假设a[i]+a[i+1]+......+a[i+k]和最大;
则a[i]一定大于等于0,否则Max = a[i+1]+......+a[i+k];
同理a[i+k]也应大于0;
由此我们可以从两头遍历,找到首尾第一个正整数;
若 a[i]+a[i+1]+......+a[i+k]和最大,则a[ i ]+a[i+1] >0否则最大值就是a[ i ]或者a[i+2] +.....a[i+k];
同理a[i]+a[i+1]+a[i+2] >0 否则 最大值就是a[i]+a[i+1]或者a[i+3] +.....a[i+k];
因此,我们可以从第一个正整数遍历。
见代码
#include<stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 50
void main(void)
{
int input[MAX];
int i,j,k;
int n=0,sum=0,max=0;
int low=0,low_sum = 0;//记录位置;
printf("input num:");
scanf("%d",&n);
printf("input data:\n");
for(i = 0;i<n;i++){
scanf("%d",&input[i]);
}
max = input[0];
for(j = 0;j<n ;j++){//找出序列开始位置,如果存在正整数,一定是以正整数开始;
if(input[j] >max ){//找出其中最大值,如果序列都为负数,直接显示结果
max = input[j];
low =j;
}
if(input[j]>=0)
break;
}
if(max >0 ){//如果max<0 说明序列都为负数;
low = j;
low_sum = j;
for(i = j;i <n; i++){
sum += input[i];
if(sum > max){
low = low_sum;
max= sum;
}
if(sum < 0){ //当sum < 0 时,前一段子序列要丢弃,从头开始。
sum = 0;
low_sum = i+1;//记录sum的起始位置
}
}
}
printf("MAX = %d \n",max);
printf("MAX seq = ");
sum = 0;
for(i = low;i<n;i++){//打印子序列
if(sum == max)
break;
sum = sum+input[i];
printf("%d ",input[i]);
}
system("pause");
return;
}
该算法很容易理解时间复杂度为O(N).