最大子序列

给定一个含有正负数的数组,求这个数组中连着的数组相加起来的最大和。最大和至少为0,即没有任何数相加。

1.最大子序列算法复杂度为O(n^3)

public static int maxSubSum1(int[] a)
{
	int maxSum = 0;
	for(int i = 0; i<a.length;i++)
	    for(j = i;j<a.length;j++){
	    	int thisSum = 0;
	    	for(int k =i;k<=j;k++)
	    		thisSum +=a[k];
	    	if(thisSum > maxSum)
	    		maxSum = thisSum;
	    }
	return maxSum;
}

2.改进算法,时间复杂度为O(n^2)

public static int maxSum2(int[] a)
{
	int maxSum = 0;
	for(int i = 0;i<a.length;i++)
	{
		int thisSum = 0;
		for(int j = i;j<a.length;j++)
		{
			thisSum +=a[j];
			if(thisSum >maxSum)
				maxSum = thisSum;
		}
	}
	return maxSum;
}


3.进阶改进算法,时间复杂度O(N logN)

该方法采用一种“分治”策略,其思想是把问题分成两个大致相等的子问题,然后递归地对他们求解,这就是“分”的部分,“治”阶段将两个子问题的解修补到一起并可能在做些少量的附加工作,最后得到整个问题的解。

在我们的例子中,最大子序列和可能在三处出现,或者整个出现在输入数据的左半部,或者整个出现在右半部,或者跨越输入数据的中部从而位于左右两半部分之中,前两种情况可以递归求解。第三种情况的最大和可以通过求出前半部分(包含前半部分最后一个元素)的最大和以及后半部分(包含后半部分第一个元素)的最大和而得到。此时将这两个和相加。

private static int maxSumRec(int[] a,int left, int right)
{
	if(left == right)
		if(a[left] > 0)
			return a[left]
		else
			return 0;

	int center =(left +right) /2;
	int maxLeftSum = maxSum(a,left,center);
	int maxRightSum = maxSumRec(a, center + 1;right);

	int maxLeftBorderSum = 0, leftBorderSum = 0;
	for(int i = center; i>= left; i--)
	{
		leftBorderSum += a[i];
		if(leftBorderSum > maxLeftBorderSum)
			maxLeftBorderSum = leftBorderSum;
	}

	int maxRightBorderSum = 0;rightBorderSum = 0;
	for(int i = center +1;i<= right;i++)
	{
		rightBorderSum += a[i];
		if(rightBorderSum >maxRightBorderSum)
			maxRightBorderSum = rightBorderSum;
	}

	return max(maxLeftSum,maxRightSum,maxLeftBorderSum+maxRightBorderSum);
}

public static int maxSubSum3(int[] a)
{
	return maxSumRec(a,0,a.length-1);
}


4.终极改进算法,时间复杂度O(n)

它只对数据进行一次扫描,一旦a[i]被读入并被处理,他就不再需要被记忆。

如果a[i]是负的,那么它不可能代表最优序列的起点,类似的,任何负的子序列不可能成为最优子序列的前缀。如果a[i]到a[j]的子序列是负的,那么可以推进i.

关键的结论是,我们不仅能够把i推进到i+1,而且实际上还可以把它一直推进到j+1.为了看清楚这一点,另p为i+1到j之间的任一下标。开始于下标p的任意子序列都不大于在下标i开始并包含从a[i]到a[p-1]的子序列的对应的子序列,因为后面这个子序列不是负的(j是使得从下标i开始其值成为负值的序列的第一个下标)。因此,把i推进到j+1是没有风险的。



public static int maxSubSum3(int[] a)
{
	return maxSumRec(a,0,a.length-1);
}

public static int maxSubSum4(int[] a)
{
	int maxSum = 0,thisSum = 0;
	for(int j = 0; j<a.length; j++)
	{
		thisSum += a[j];
		if(thisSum >maxSum)
			maxSum = thisSum;
		else if(thisSum < 0)
			thisSum = 0;
	}
	return maxSum;
}











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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值