最大连续子序列和

本文介绍了四种解决最大子序列和问题的算法:穷举法、改进的穷举法、递归法(分治法)和在线处理(动态规划)。通过详细解释每种算法的原理和复杂度,展示了如何在不同场景下选择合适的解决方案,并提供了测试用例验证算法的有效性。
摘要由CSDN通过智能技术生成

Question:

输入一组整数,求出这组数字子序列和中最大值。也就是只要求出最大子序列的和,不必求出最大的那个序列。例如:

序列:-2 ,11, -4, 13, -5, -2,则最大子序列和为20。

序列:-6 ,2, 4, -7, 5, 3, 2 ,-1 ,6, -9 ,10 ,-2,则最大子序列和为16。

算法1:穷举法

/**
	 * 穷举法
	 * 时间复杂度0(n^3)
	 * @param arr
	 * @return
	 */
	public static int maxSubseqSum1(int[] arr){
		int thisSum,maxSum = 0;
		int i,j,k;
		for (i = 0; i < arr.length; i++) {//i是子列左端位置
			for (j = i; j < arr.length; j++) {//j是子列右端位置
				thisSum = 0;//thisSum是从arr[i]到a[j]的子列和
				for (k = i; k < j; k++) {
					thisSum += arr[k];
				}
				if (thisSum > maxSum) {//如果刚得到这个子列和更大
					maxSum = thisSum;//则更新结果
				}//j循环结束
			}//i循环结束
		}		
		return maxSum;
	}

算法2:改进的穷举法,去掉一层for循环,去掉重复操作

/**
	 * 穷举法之二。也是一种穷举法,相比较第一种穷举法撤出了一层for循环,更加直观。而且没有多余重复的操作
	 * 时间复杂度0(n^2)
	 * @param arr
	 * @return
	 */
	public static int maxSubseqSum2(int[] arr){
		int thisSum,maxSum = 0;
		int i,j;
		for (i = 0; i < arr.length; i++) {//i是子列左端位置
			thisSum = 0; //thisSum是从arr[i]到arr[j]的子列和
			for (j = i; j < arr.length; j++) {//j是子列右端位置
				thisSum += arr[j];
				/*对于相通的i,不同的j,只要在j-1次循环的基础上累加1项即可*/
				if (thisSum > maxSum) {//如果刚得到这个子列和更大
					maxSum = thisSum;//则更新结果
				}
			}//j循环结束
		}//i循环结束		
		return maxSum;
	}

算法3:递归法(分治法)

声明:这里借鉴别人的博文:分治法借鉴博客

/**
	 * 分而治之
	 * 时间复杂度0(nlogn)
	 * @param arr
	 * @return
	 */
	public static int maxSubseqSum3(int[] arr,int left,int right){
		if (left == right) {
			if (arr[left] > 0) {
				return arr[left];
			}else{
				return 0;
			}	
		}
		
		int center = (left+right)/2;
		int maxleftSum = maxSubseqSum3(arr, left, center);
		int maxRightSum = maxSubseqSum3(arr, center+1, right);
		
		//求出以左边对后一个数字结尾序列的最大值
		int maxleftBorderSum = 0,leftBorderSum = 0;
		for (int i = center; i >= left; i--) {
			leftBorderSum += arr[i];
			if (leftBorderSum > maxleftBorderSum) {
				maxleftBorderSum = leftBorderSum;
			}
		}
		
		//求以右边对后一个数字结尾的序列最大值
		int maxRightBorderSum = 0,rightBorderSum = 0;
		for (int j = center+1; j <= right; j++) {
			rightBorderSum += arr[j];
			if (rightBorderSum > maxRightBorderSum) {
				maxRightBorderSum = rightBorderSum;
			}
		}
		
		//返回左边最大,右边最大,和跨域最大的一个数字
		int sum = maxleftBorderSum+ maxRightBorderSum;
		
		if(maxleftSum >= maxRightSum && maxleftSum >= sum)
			return maxleftSum;
		else if(maxRightSum >= maxleftSum && maxRightSum >= sum)
			return maxRightSum;
		else
			return sum;
	}

算法4:在线处理(动态规划)

将子序列与其子子序列进行问题分割, 得到状态转移方程:MaxSum[i] = max{MaxSum[i-1]+A[i],MaxSum[i-1]+A[i]}

其中MaxSum[i]表示数组前i-1个元素的和

/**
	 * 在线处理
	 * 时间复杂度0(n)  线性算法
	 * @param arr
	 * @return
	 */
	public static int maxSubseqSum4(int[] arr){
		int thisSum = 0,maxSum = 0;
		int i,j;
		for (i = 0; i < arr.length; i++) {//i是子列左端位置
			thisSum += arr[i]; //向右累加
			if(thisSum > maxSum)
				maxSum = thisSum;//发现更大和则更新当前结果
			else if(thisSum < 0)//如果当前子列和为负数
				thisSum = 0;//则不可能使后面的部分和增大,抛弃之
		}//i循环结束		
		return maxSum;
	}

简单测试用例:由于时间较短,所以采用循环运行N次的办法累加时间

public static void main(String[] args) {
		int[] arr1 = new int[] { -2, 11, -4, 13, -5, -2 };
		int[] arr2 = new int[] { -6, 2, 4, -7, 5, 3, 2, -1, 6, -9, 10, -2, 2, 4, -7, 5, 3, 2, -1, 6, -9, 10, -2, 2, 4,
				-7, 5, 3, 2, -1, 6, -9, 10, -2, 2, 4, -7, 5, 3, 2, -1, 6, -9, 10, -2, 2, 4, -7, 5, 3, 2, -1, 6, -9, 10,
				-2, 2, 4, -7, 5, 3, 2, -1, 6, -9, 10, -2, 2, 4, -7, 5, 3, 2, -1, 6, -9, 10, -2, 2, 4, -7, 5, 3, 2, -1,
				6, -9, 10, -2, 2, 4, -7, 5, 3, 2, -1, 6, -9, 10, -2, 2, 4, -7, 5, 3, 2, -1, 6, -9, 10, -2, 2, 4, -7, 5,
				3, 2, -1, 6, -9, 10, -2, 2, 4, -7, 5, 3, 2, -1, 6, -9, 10, -2, 2, 4, -7, 5, 3, 2, -1, 6, -9, 10, -2, 2,
				4, -7, 5, 3, 2, -1, 6, -9, 10, -2, 2, 4, -7, 5, 3, 2, -1, 6, -9, 10, -2, 2, 4, -7, 5, 3, 2, -1, 6, -9,
				10, -2, 2, 4, -7, 5, 3, 2, -1, 6, -9, 10, -2, 2, 4, -7, 5, 3, 2, -1, 6, -9, 10, -2, 2, 4, -7, 5, 3, 2,
				-1, 6, -9, 10, -2, 2, 4, -7, 5, 3, 2, -1, 6, -9, 10, -2, 2, 4, -7, 5, 3, 2, -1, 6, -9, 10, -2, 2, 4, -7,
				5, 3, 2, -1, 6, -9, 10, -2, 2, 4, -7, 5, 3, 2, -1, 6, -9, 10, -2, 2, 4, -7, 5, 3, 2, -1, 6, -9, 10, -2,
				2, 4, -7, 5, 3, 2, -1, 6, -9, 10, -2, 2, 4, -7, 5, 3, 2, -1, 6, -9, 10, -2, 2, 4, -7, 5, 3, 2, -1, 6,
				-9, 10, -2, 2, 4, -7, 5, 3, 2, -1, 6, -9, 10, -2, 2, 4, -7, 5, 3, 2, -1, 6, -9, 10, -2 };

		int N = 1000;// 测试算法执行次数
		System.out.println("maxSubseqSum1:" + maxSubseqSum1(arr2));
		System.out.println("maxSubseqSum2:" + maxSubseqSum2(arr2));
		System.out.println("maxSubseqSum3:" + maxSubseqSum3(arr2, 0, arr2.length - 1));
		System.out.println("maxSubseqSum4:" + maxSubseqSum4(arr2));

		long timeStart1 = System.currentTimeMillis();
		for (int i = 0; i < N; i++) {
			maxSubseqSum1(arr2);
		}
		long timeEnd1 = System.currentTimeMillis();
		System.out.println("算法1执行" + N + "次的时间,单位毫秒:" + (timeEnd1 - timeStart1));

		long timeStart2 = System.currentTimeMillis();
		for (int i = 0; i < N; i++) {
			maxSubseqSum2(arr2);
		}
		long timeEnd2 = System.currentTimeMillis();
		System.out.println("算法2执行" + N + "次的时间,单位毫秒:" + (timeEnd2 - timeStart2));

		long timeStart3 = System.currentTimeMillis();
		for (int i = 0; i < N; i++) {
			maxSubseqSum3(arr2, 0, arr2.length - 1);
		}
		long timeEnd3 = System.currentTimeMillis();
		System.out.println("算法3执行" + N + "次的时间,单位毫秒:" + (timeEnd3 - timeStart3));

		long timeStart4 = System.currentTimeMillis();
		for (int i = 0; i < N; i++) {
			maxSubseqSum3(arr2, 0, arr2.length - 1);
		}
		long timeEnd4 = System.currentTimeMillis();
		System.out.println("算法4执行" + N + "次的时间,单位毫秒:" + (timeEnd4 - timeStart4));
	}

测试环境:

java version "1.8.0_66"

Java(TM) SE Runtime Environment (build 1.8.0_66-b17)

Java HotSpot(TM) 64-Bit Server VM (build 25.66-b17, mixed mode)

OS:windows10

Eclipse:4.5.2

测试结果:

031707_Hzy4_2303497.png

转载于:https://my.oschina.net/u/2303497/blog/657760

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值