最大子序列和问题

这是在《数据结构与算法分析 Java语言描述中文第二版》里的一个问题。本文记载我对书中该问题的第四种解法的理解。

问题:

分析:数列的最大子序列必定是以j结尾的,其中,j属于[A1,AN]。首先,我们计算出以j结尾的子序列中的最大子序列的和;然后,因为j有N个值,也就是说第一步得到N最大子序列的和,这N个值中最大的那一个就是最终答案。从N个数中找出最大值是很容易的。关键是,在以j结尾的子序列中,哪一个是最大的。下面来分析解决这个问题。


局部看:

存在子序列:A1,A2,A3...Ai...A(j-1),Aj。我们现在的问题是,求这个序列的以Aj结尾的子序列的和中的最大值?

                            Sum = Aj + A(j-1) + ...Ai...+ A3 + A2 + A1;

其中,只有Aj是必须的。

我们的目的去掉A1,A2,A3...,使得Sum值最大。我们知道,减去一个负数可以使一个数变大,所以如果A1 + A2 + A3 + ... A(i-1)< 0,那么:

                       Aj + A(j-1) + ...Ai > Aj + A(j-1) + ...Ai...+ A3 + A2 + A1;

如果Ai + ...  + A(k-1) < 0,其中k < j。那么:

                      Aj + A(j-1) + ...Ak >Aj + A(j-1) + ...Ai;

也就是说,不断去掉和为负的前缀序列,以Aj结尾的子序列的和就会不断变大。当所有和为负的前缀序列都去掉时,以Aj结尾的子序列的和就变到最大了。因为这时,Aj结尾的子序列的任意前缀序列的和都是大于等于0的,减去任意前缀序列最多使和不变,甚至变小。

此时,我们找到了求这个序列的以Aj结尾的子序列的和的最大值的方法,就是去掉序列中所有和为负的前缀序列。


全局看:

                 Sum(j-1) = A(j-1) + ...Ai...+ A3 + A2 + A1;

                  Sum(j) = Aj +Sum(j-1);

如果Sum(j-1)< 0,就应该去掉。


结合源代码来做个总结:

public int maxSubSum(int[] a) {
		int maxSum = 0;
		int thisSum = 0;
		for(int j = 0; j < a.length; j++) {
			thisSum += a[j];
			if(thisSum > maxSum) {
				maxSum = thisSum;
			}
			// 和为0的序列不可能是最大子序列的前缀,删掉
			if(thisSum < 0) {
				thisSum = 0;
			}
		}
		return maxSum;
	}

for循环的每一次迭代计算一个以Aj结尾的序列的最大子序列和thisSum。如果thisSum < 0,这个值将被设为0,也就是说,它所代表的序列不能作为以Aj后面的元素结尾的序列的最大子序列的前缀。按照这个过程,其实,在计算以Aj结尾的序列的最大子序列和thisSum时,Aj所有和为负的前缀序列都去掉了。


书中阐释这个算法正确性的部分的意思是这样的:和为负的序列不可能作为最大子序列的前缀,并且,存在序列Ai,A(i+1),A(i+2),A(i+3)...A(j-1),Aj。如果Ai,A(i+1),A(i+2),A(i+3)...A(j-1),不能作为Aj的前缀序列,那么A(p)...A(j-1)也不能作为Aj的前缀,其中i<p<j。因为如果Ai+A(i+1)+A(i+2)+A(i+3)+ ...+ A(j-1)<0的话,那么A(p)+...+A(j-1)<0也是成立的,因为Ai...A(p-1)作为另一个可能的最大子序列的前缀,该序列的和必定大于等于0。Ai,A(i+1),A(i+2),A(i+3)...A(j-1)少了Ai...A(p-1)不可能使数列的和变大。

我认为从这个解释直接到上面的代码跨度太大了,所以才有上文更仔细的解释。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值