最大字段和的3中解法

问题描述:

    给定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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值