最大子段和

问题描述:

给定n个整数(可能为负数)组成的序列a[1], a[2], a[3],…, a[n], 求该序列如a[i]+a[i+1]+…+a[j]的子段和的最大值。当所给的整均为负数时定义子段和为0,

例如,当(a[1],a[2],a[3],a[4],a[5],a[6])=(-2,11,-4,13,-5,-2)时,最大子段和为20。

思路分析:

一、蛮力算法:

该算法思想是枚举的思想,将所有的子段和求一遍,依次比较,将子段和大的作为结果返回。实现该算法思想主要是找到子段左右两端的下标(i,j)。该算法可以改进:由于(a[i]+a[i+1]+…+a[j]) = a[j]+( a[i]+a[i+1]+…+a[j-1]),

避免重复计算,用变量thissum记录( a[i]+a[i+1]+…+a[j-1])的值。

改进前时间复杂度:O(n^3)

改进后时间复杂度:O(n^2)

 

二、分治法:

将数组a[n] 分为a[1..n/2]和a[n/2+1..n],分别求两端的最大子段和,a[1..n]的最大子段和有三种情况:

  1. a[n]的最大子段和与a[1..n/2]的最大子段和相同。
  2. a[n]的最大子段和与a[n/2+1..n]的最大子段和相同。
  3. a[n]的最大子段和是(a[i]+a[i+1]+…+a[j]),且1<=i<=n/2, n/2+1<=j<=n。

时间复杂度:O(n*logn)

 

三、动态规划法:

b[j]=max{(a[i]+a[i+1]+…+a[j])}, ( 1<=j<=n)。有b[j]定义知,当b[j-1]>0, b[j]= b[j-1]+a[j],否则b[j]=a[j]。即:

b[j]= max{ b[j-1]+a[j],a[j]}

时间复杂度:O(n)

 

代码:

一、蛮力算法

int MaxSum(int *a, int n, int &besti, int &bestj){
	int sum = 0;
	for(int i=1; i<=n; i++){
		for(int j=i; j<=n; j++){
			int thisSum = 0;
			for(int k=i; k<=j; k++){
				thisSum += a[k];
			}
			if(thisSum>sum){
				sum = thisSum;
				besti = i;
				bestj = j;
			}
		}
	}
	return sum;
}

改进后:
int MaxSum(int *a, int n, int &besti, int &bestj){
	int sum = 0;
	for(int i=1; i<=n; i++){
		int thisSum = 0;
		for(int j=i; j<=n; j++){
			thisSum += a[j];
			if(thisSum>sum){
				sum = thisSum;
				besti = i;
				bestj = j;
			}
		}
	}
	return sum;
}

 

二、分治法

int MaxSum(int *a, int left, int right){
	int sum = 0;
	if(left == right) {
		sum = a[left]>0? a[left]:0;
	}else{
		int center = (left+right)/2;
		int leftSum = MaxSum(a,left,center);
		int rightSum = MaxSum(a, center+1,right);
		int s1 = 0;
		int lefts = 0;
		for(int i=center;i>=left;--i){
			lefts += a[i];
			if(lefts>s1) s1 = lefts;
		}
		int s2 = 0;
		int rights = 0;
		for(int i=center+1;i<=right;++i){
			rights += a[i];
			if(rights>s2) s2 = rights;
		}
		sum = s1+s2;
		if(sum<leftSum) sum = leftSum;
		if(sum<rightSum) sum = rightSum;
	}
	return sum;
}

三、动态规划

int MaxSum(int *a, int n){
	int sum = 0, b = 0;
	for(int i = 1; i <= n; i++){
		if(b>0) b += a[i];
		else b = a[i];
		if(b>sum) sum = b;
	}
	return sum;
}

 

测试用例:

int a[] = {0,-1,-2l,23,-4,-5,10}

测试结果:

 

  • 0
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值