题目:
输入一个整形数组,数组里有正数也有负数。
数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和。
求所有子数组的和的最大值。要求时间复杂度为O(n)。
例如输入的数组为1, -2, 3, 10, -4, 7, 2, -5,和最大的子数组为3, 10, -4, 7, 2,
因此输出为该子数组的和18。
//July 2010/10/18
还有全是负数时。
错误的方法及分析:a[MAX]={1, -2, 3, 10, -4, 7, 2, -5};
dp[0]=a[0];for (i=1; i<8; i++)
dp[i]=max(dp[i-1],(dp[i-1]+a[i]));是错误的,这里面当遇到负数时,会跳过,不计算,则不是连续的子数组。
这个结果是错误的,结果如下:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |
a | 1 | -2 | 3 | 10 | -4 | 7 | 2 | -5 |
dp | 1 | 1 | 4 | 14 | 14 | 21 | 23 | 23 |
正确的方法及分析:
其中,start[1]为包含A[1]的和的最大一段数组,则start[0]为包含A[0]的和的最大一段数组,而All[1]为A[1]-------A[n-1]中和的最大的一段数组,则All[0]为A[0]-------A[n-1]中和的最大的一段数组。
而All[0]=max{start[0],All[1]},且start[0]=max{A[0],A[0]+start[1]}。
故可知All[i]=max{start[i],All[i+1]},且start[i]=max{A[i],A[i]+start[i+1]}。
由start[i]=max{A[i],A[i]+start[i+1]}可知,start[i]需要由start[i+1]求出,故此例为从右到左计算;其中当start[i+1]<0时,start[i]=A[i],start[i+1]为从A[i+1]开始并包含A[i+1]的和的最大一段数组,我们可以用sum来表示,这样,只需o(1)的空间即可,而不是o(n)的空间;当start[i+1]<0时,即从A[i+1]开始且包含A[i+1]的最大和小于0,即sum<0时,sum=A[i];用max来表示All之后由后向前开始计算。
程序如下:
int Max(int x,int y)
{
return x>y?x:y;
}
int MaxSum(int *A,int n)
{
sum=A[n-1];
max=A[n-1];
for (i=n-2; i>=0; i--)
{
sum=Max(A[i],sum+A[i]);
max=Max(sum,max);
}
}
上式也可以换个写法,同样从右向左,
int Maxsum(int *A,int n)
{
sum=A[n-1];
max=A[n-1];
for (i=n-2; i>=0; i--)
{
if (sum<0)
{
sum=A[i];
}
else
{
sum+=A[i];
}
/*或者if...else...写成下面这样
if(sum<0)
{
sum=0;
}
sum+=A[i];
*/
if (sum>max)
{
max=sum;
}
}
return max;
}
当然,也可以从左到右计算,图例如下:
All[n-1]=max{All[n-2],end[n-1]},end[n-1]=max{end[n-2]+A[n-1],A[n-1]},
由此推出:All[i]=max{All[i-1],end[i]},end[i]=max{end[i-1]+A[n-1],A[n-1]}。
包含A[i]的累加和最大用sum表示,当sum<0时,sum=A[i+1],在和max比较。
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |
1 | -2 | 3 | 10 | -4 | 7 | 2 | -5 | |
sum | 1 | -1 | 3 | 13 | 9 | 16 | 18 | 13 |
max | 1 | 1 | 3 | 13 | 13 | 16 | 18 | 18 |
start | 0 | 0 | 2 | 2 | 2 | 2 | 2 | 2 |
end | 0 | 0 | 2 | 3 | 3 | 5 | 6 | 6 |
正确代码如下:从左向后
#include<stdio.h>
#include<stdlib.h>
#define MAX 100
int main()
{
int i,max,sum,start,end;
int a[MAX]={-11, -2, -3, -10, -4, -7, -2, -5};
max=a[0]; sum=a[0]; start=0; end=0;
for (i=1; i<8; i++)
{
if (sum<0)
{
sum=a[i];
start=i;
}
else
{
sum+=a[i];
}
if (sum>max)
{
max=sum;
end=i;
}
}
printf("max=%d\n",max);
if (start>end)
{
start=end;
}
printf("start=%d end=%d\n",start,end);
system("pause");
}
max=-2
start=1 end=1
如:a[MAX]={1, -2, 3, 10, -4, 7, 2, -5};
则max=18
start=2 end=6