最大连续和问题

此处介绍四种方法,复杂度in descending order
一、O(n^3)
普通做法;
即在数组中,遍历起始和终止位置,然后从起始到终止位置累加求和,求得的sum与最大值比较,如果比最大值大,就赋值;

int best = 0;//ans
for(int i = 1; i <= n; i++)
	for(int j = i; j <= n; j++)
	{
		int sum = 0;
		for(int k = i; k <= j; k++) sum += A[k];
		if(sum > best) best = sum;
	}

二、O(n^2)
用前缀和,从起始到终止的求和过程所求得的sum,即为终止的前缀和减去(起始位置-1)的前缀和所得的值;
那么在开始遍历前,我们只要先求出前缀和,然后再遍历,用前缀和来减就可以;

s[0] = 0;
for(int i = 1; i <= n; i++)
	s[i] = s[i-1] + A[i];
for(int i = 1; i <= n; i++)
	for(int j = i; j <= n; j++)
		maxs = max(maxs, s[j] - s[i-1]);

三、O(nlogn)
分治的思想,找到左一半的最大连续和和右一半的最大连续和,然后归并;

int maxm(int *A, int x, int y)
{
	if(y - x == 1) return A[x];
	int m = x + (y - x)/2;//划分区间,[x,m),[m,y);
	int maxs = max(maxm(A,x,m), maxm(A,m,y));//继续划分区间; 
	int v, L, R;
	v = 0;
	L = A[m-1];
	for(int i = m-1; i >= x; i--) L = max(L, v+=A[i]);//左一半的最大连续和; 
	v = 0;
	R = A[m];
	for(int i = m; i <= y; i++) R = max(R, v+=A[i]);//右一半的最大连续子段和; 
	return maxs = max(maxs,L+R);
}

对于分治时间复杂度的计算
T(n) = 2T(n/2) + n;
…… = 2
(2T(n/4) + n/2) +n;
…… = 4
T(n/4) + 2n;
…… = 4
(2*(T(n/8) + n/4) + 2n;
…… = 8
T(n/8) + 3n;
…… = 2^k
T(n/2的k次方) + kn;//直到2^k== n;此时k = log(2,n);
…… = n
T(1) + nlog(2,n);
…… = n
logn + n;
四、O(n)
第四种方法是在第二种方法的基础上加以改进,实际上我们求最大连续子段和,就是求最大的s[j] - s[i-1],那么当j确定时,要使s[j] - s[i - 1]最大,那么s[i-1]应该最小,只要遍历前缀和数组维护最小的s就可以;

s[0] = 0;
for(int i = 1; i <= n; i++)
	s[i] = s[i-1] + A[i];
int mins = 0;
for(int i = 1; i <= n; i++)
{
	mins = min(mins,s[i-1])
	best = max(best,s[i] - mins);
}
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值