最大子段和

对于最大子段和,就是取一个数组中(包括负整数)a1,a2,a3,...,an中和最大的一段。想法很简单,两个变量M,N,每次加一个ai的时候先判断M是否大于0,大于的时候加上ai,否则等于ai,然后每次判断N是否小于M,是的话就保存M。代码实现如下。

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

然后问题延伸到最大m子段和。这个m是说有m段子段(子段不相交)之和为最大。条件和上面一样。其实上面就是这个m取特殊值m=1的时候。先想到用动态规划去解,所以假设一个二维数组b[i,j]用来保存最大子段和。分析之后发现:b[i,j]的最后一个子段只有两种情况。一种是只有a[j],一种是不只有a[j].所以b[i,j]的递归公式为:

b[i,j]=b[i,j-1]+a[j]        //包含aj




b[i,j]=b[i-1,t]+a[j] //(1<=t<=m) //不包含aj。


最后发现如果用二维数组其实每次只有i-1和i行用的到。所以直接用两个一维数组就可以解决问题。代码实现如下。

//对于最大m子段和,假设用b[i,j]标识。但经分析分为第i子段包含/不包含b[j]情况。所以仅用2个数组保存即可。公式
//if(包含b[j])  =>b[i,j-1]+a[j]
//else =>b[i-1,t]+a[j]   //i ≤ j ≤ n,i − 1 ≤ t < j
int  Max_m_SubSum(int m,int n,int *a)   // 最大m字段和。参数:m:子段个数、n:元素个数、a:数组。
{
	if (n < m || m < 1) return 0;
	int * b = new int[n+1]; //保存当前最大。
	int * c = new int[n+1];//保存前一次最大。
	b[0] = 0;
	c[1] = 0;
	//init

	for (int i = 1; i <= m; i++)//由1到m,为一个子段范围。
	{
		b[i] = b[i - 1] + a[i];// b每次加上一个ai。
		c[i - 1] = b[i];//c[i-1]保存b[i].	
		int max = b[i];//max保存bi
		for (int j = i + 1; j <= i + n - m; j++) //设置为i+n-m。
		{
			b[j] = b[j - 1] > c[j - 1] ? b[j - 1] + a[j] : c[j - 1] + a[j];//判断取当前最大加上aj还是前一个加上aj。
			c[j - 1] = max;//此时c[i-1]更新。
			if (max < b[j]) max = b[j];//如果max小于bj,更新max。
		}
		c[i + n - m] = max;//最后一个c[i+n-m]保存max,在下一次循环中使用比较。
	}

	int sum = 0;
	for (int j = m; j <= n; j++)
	{
		if (sum < b[i]) sum = b[j];
	}
	return sum;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值