问题描述:
给定n个整数,组成序列a[1], a[2], a[3], ... a[n],求形如a[i]+a[i+1]+...+a[j]的字段和的最大值。
// 最大子段求和,穷举法,复杂度O(n^2)
// 输入参数:a[]保存数据,其中a[0]保存数据个数
// 返回值:返回最大子段的和值
long MaxSum0(int a[])
{
int i, j; // 在[i,j]区间求字段和
int sum = 0;
long max = -200000L;
// 三重循环:第一重是左边界循环,第二重是右边界循环,第三重是累加循环
for(i = 1; i <= a[0]; i ++)
{
sum = 0;
for(j = i; j <= a[0]; j ++)
{
sum += a[j];
if(max < sum)
max = sum;
}
}
return max;
}
// 最大子段求和,分治法,复杂度O(nlog(n))
// 将a[1...n]分为两部分a[1...n/2]和a[n/2+1...n],则a[1...n]的最大子段会有三种情况:
// (1) a[1...n]的最大子段会是a[1...n/2]的最大子段
// (2) a[1...n]的最大子段会是a[n/2+1...n]的最大子段
// (3) a[1...n]的最大子段会是a[i...j],其中1<=i<=n/2, n/2+1<=j<=n
// T(n) = 2T(n/2) + O(n)
// T(n) = O(nlog(n))
// 输入参数:a[]保存数据,其中a[0]保存数据个数;l为子段的左边界;r为子段的右边界
// 返回值:返回最大子段的和值
long MaxSum1(int a[], int l, int r)
{
int center = (l+r)/2; // 子段的中间索引
long lMax = 0, rMax = 0; // 左右区间的最大子段和值
long sum0, sum1, max0, max1, mMax; // 中部区间的最大子段和值
long max = 0;
if(l == r) // 如果是一个数,那最大子段和就是本身
return a[l];
else
{
lMax = MaxSum1(a, l, center); // 迭代调用MaxSum1求取左区间的最大和值
rMax = MaxSum1(a, center+1, r); // 迭代调用MaxSum1求取右区间的最大和值
// 求取中部区间的最大和值
// 从center向左求最大和值
max0 = -20000L;
sum0 = 0;
for(int i = center; i >= l; i --)
{
sum0 += a[i];
if(max0 < sum0)
max0 = sum0;
}
// 从center+1向右求最大和值
max1 = -20000L;
sum1 = 0;
for(int i = center+1; i <= r; i ++)
{
sum1 += a[i];
if(max1 < sum1)
max1 = sum1;
}
mMax = max0 + max1; // 中部区间的最大和值
max = mMax;
if(lMax > max)
max = lMax;
if(rMax > max)
max = rMax;
return max;
}
}
// 最大子段求和,动态规划法,复杂度O(n)
// b[j] = a[i] + ... + a[j], 1<=i<=j, 1<=j<=n, 则最大子段和即是max b[j], 1<=j<=n
// 若b[j-1]<=0, 则b[j] = a[j]; 若b[j-1]>0, 则b[j] = b[j-1] + a[j]
// T(n) = O(n)
// 输入参数:a[]保存数据,其中a[0]保存数据个数
// 返回值:返回最大子段的和值
long MaxSum2(int a[])
{
int max;
int b;
max = b = a[1];
for(int i = 2; i <= a[0]; i ++)
{
if(b <= 0)
b = a[i];
else
b += a[i];
if(max < b)
max = b;
}
return max;
}