问题描述:有一串数字,可正可负也可为0,连续两个或多个数字组成了一个子
序列,每个子序列都有一个和,求出所有子序列中和最大的一个。
例如输入的数组为3 6 -7 -1 4 3 -2 -5 10 -3,则和最大的子序列为3 6 -7 -1
4 3 -2 -5 10,最大和为11
分析: 这个问题容易想到的方法是计算出任意两点之间的序列和,取出它们中的最大值,
时间复杂度为O(n^2)
程序员编程艺术上提到一种二分的方法,将序列分成左右两个部分,分别计算出
左右两个部分的连续最长子序列,再求出端点分别在左右两边的连续最长子序列,
它们三个中的最大值就是整个序列上的最长连续子序列,时间复杂度是O(nlogn)
#include <stdio.h>
#define M 100
int a[M];
int max_sum(int left,int right)
{
int leftmax,rightmax;
int leftside,rightside;
int leftsidemax, rightsidemax;
if(left==right)
return a[left]>0?a[left]:0;
leftside=leftsidemax=0;
rightside=rightsidemax=0;
int middle=(left+right)/2;
leftmax=max_sum(left,middle);
rightmax=max_sum(middle+1,right);
for(int i=middle;i>=left;i--)
{
leftside+=a[i];
if(leftside>leftsidemax)
leftsidemax=leftside;
}
for(int i=middle+1;i<=right;i++)
{
rightside+=a[i];
if(rightside>rightsidemax)
rightsidemax=rightside;
}
int maxside=leftmax>rightmax?leftmax:rightmax;
int middleside=leftsidemax+rightsidemax;
int max=maxside>middleside?maxside:middleside;
return max;
}
int main()
{
freopen("in","r",stdin);
int n;
scanf("%d", &n);
for(int i = 0; i < n; i++)
scanf("%d", &a[i]);
int max = max_sum(0, n-1);
printf("%d\n", max);
}
将数字存放在数组中,下标从0到n-1,假如已经求出以i为末尾的最大连续子序
列之和为sum[i],则如果要求以i+1为结尾的最大连续子序列的和sum[i+1],有
sum[i+1]=sum[i]>0 ? sum[i]+a[i+1] : a[i+1];找出它们中的最大值
int a[M];
int sum[M];
int max_sum(int left, int right)
{
int max=0; #考虑全是负数的情况改为max=a[left]
sum[left]=a[left];
for(int i=left+1;i<=right;i++)
{
sum[i]=sum[i-1]>0?sum[i-1]+a[i]:a[i];
if(sum[i]>max)
max=sum[i];
}
return max;
}