算法分析——最大连续子序列和的问题

最大连续子序列求和问题

问题引出:

给定整数A1,A2A3···AN(可能有负数),求解的最大值。如果所有的整数全是负数,则最大连续子序列的和为零。

举个例子,如果输入{-211-413-52},那么答案是20,它代表的连续序列是从第2项至第4项。再举一个例子,输入为{1-34-2-16},那么答案是7,这个子序列包括最后4项。

·简单的O(N3)算法

·改进的O(N2)算法

·线性算法

Ai,j是任意一个子序列,它包含的元素从ij,设Si,j是Ai,j的和。

则有如下结论:

1.Ai,j是任意Si,j < 0的序列,如果q > j ,那么Ai,q 肯定不是最大连续子序列。(因为如果Si,j < 0,那么最大连续子序列完全可以排除Ai,j 这些元素,取之后的人一个非负元素作为最大连续子序列)

2.对于任意i,设Ai,j 是一个序列,且Si,j < 0 ,那么,对于任意i <= p <= j ,且 p <= q, 那么Ap,q要么不是最大连续子序列的和,要么等于已出现的最大连续子序列。

证明如下:

如果 p = i,则应用结论。否则,有Si,q = Si,p-1 + Sp,q 。因为Si,j < 0  j是最低的下标,所以Si,p-1 >= 0。因此Sp,q  <= Si,q 。当q > j时,有结论1知,Aiq 不是最大连续子序列,而由Sp,q  <= Si,q 得知,Ap,q也不是最大连续子序列。如果q <= j,Ap,q 的和最多与已出现的子序列Aiq 的和相等。

据以上两个结论,可以得到优化的线性算法


package com.zgy.datastructures.maxsubsequence;

/**
 * 
 * @author yaguanzhou
 * @version 1.0
 * 
 */
public class MaxSubSequence {

	public static int start = 0;
	public static int end = 0;

	public static void main(String[] args) {
		int[] testArray = { 1, -3, 8, 11, -5, 21, 19, -20 };
		int max_n3 = maxSubSequenceSum_N3(testArray);
		System.out.println("最大子序列:" + "从 第" + (start + 1) + "到第" + (end + 1)
				+ "个元素,子序列的和为:" + max_n3);

		int max_n2 = maxSubSequenceSum_N2(testArray);
		System.out.println("最大子序列:" + "从 第" + (start + 1) + "到第" + (end + 1)
				+ "个元素,子序列的和为:" + max_n2);

		int max_n1 = maxSubSequenceSum_N1(testArray);
		System.out.println("最大子序列:" + "从 第" + (start + 1) + "到第" + (end + 1)
				+ "个元素,子序列的和为:" + max_n1);
	}

	/**
	 * 此方法的时间复杂度为N的3次方
	 * 
	 * @param int[] arr
	 * @return maxSum
	 */
	public static int maxSubSequenceSum_N3(int[] arr) {
		int maxSum = 0;// 最大子序列的和
		for (int i = 0; i < arr.length; i++) {// 从数组中的第一个元素开始循环
			for (int j = i; j < arr.length; j++) {// 从当前元素开始,叠加其后的元素
				int currentSum = 0;
				for (int k = i; k <= j; k++) {// 从当前元素开始叠加到其后特定位置上的元素
					currentSum += arr[k];
				}
				if (currentSum > maxSum) {
					maxSum = currentSum;
					start = i;
					end = j;
				}
			}
		}
		return maxSum;
	}

	/**
	 * 此方法的时间复杂度为N的2次方
	 * 
	 * @param int[] arr
	 * @return maxSum
	 */
	public static int maxSubSequenceSum_N2(int[] arr) {
		int maxSum = 0;// 最大子序列的和
		for (int i = 0; i < arr.length; i++) {// 从数组中的第一个元素开始循环
			int currentSum = 0;
			for (int j = i; j < arr.length; j++) {// 从当前元素开始,叠加其后的元素
				currentSum += arr[j];
				if (currentSum > maxSum) {
					maxSum = currentSum;
					start = i;
					end = j;
				}
			}
		}
		return maxSum;
	}

	/**
	 * 此方法的时间复杂度为O(N)
	 * 
	 * @param int[] arr
	 * @return maxSum
	 */
	public static int maxSubSequenceSum_N1(int[] arr) {
		int maxSum = 0;// 最大子序列的和
		int currentSum = 0;
		for (int i = 0, j = 0; j < arr.length; j++) {// 从数组中的第一个元素开始循环
			currentSum += arr[j];

			if (currentSum > maxSum) {
				maxSum = currentSum;
				start = i;
				end = j;
			} else if (currentSum < 0) {//如果叠加得到和小于0,则舍弃之前的元素,往后继续叠加
				i = j + 1;
				currentSum = 0;
			}
		}
		return maxSum;
	}
}


输出:

最大子序列:从 第3到第7个元素,子序列的和为:54
最大子序列:从 第3到第7个元素,子序列的和为:54
最大子序列:从 第3到第7个元素,子序列的和为:54


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值