经典最大子序列和问题

//最大子序列和问题的四种算法
//注意以下算法只是求出最大的和,并没有找出对应的子序列
public class MaxSubSum {

	public static void main(String[] args) {
		int[] a = { 4, -3, 5, -2, -1, 2, 6, -2 };
		System.out.println(maxSubSum1(a));
		System.out.println(maxSubSum2(a));
		System.out.println(maxSubSum3(a));
		System.out.println(maxSubSum4(a));
	}

	// 算法一,穷举法,运行时间 O(N^3)
	public static int maxSubSum1(int[] a) {
		int maxSum = 0;
		for (int i = 0; i < a.length; i++) {
			for (int 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;
	}

	// 算法二,穷举法的改进,与算法一没有本质区别
	// 由三层循环改为两层,运行时间O(N^2)
	public static int maxSubSum2(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;
	}

	// 算法三,采用递归思想和分治(divide-and-conquer)策略
	// 如果把序列从中间分为两部分,那么最大子序列和可能在三处出现,要么整个出现在输入数据的左半部,要么整个出现在右半部,
	// 要么跨越分界线。前两种情况可以递归求解,第三种情况的最大和可以通过求出前半部分(包括前半部分的最后一个元素)的最大
	// 和以及后半部分(包含后半部分的第一个元素)的最大和而得到,此时将两个和相加。
	// 运行时间O(NlogN)
	public static int maxSubSum3(int[] a) {
		return maxSumRec(a, 0, a.length - 1);
	}

	private static int maxSumRec(int[] a, int left, int right) {

		// 基准情况(也叫终止条件)
		if (left == right)
			return a[left] > 0 ? a[left] : 0;

		// 分成两个子问题
		int center = (left + right) / 2;
		// 递归求解
		int maxLeftSum = maxSumRec(a, left, center);
		int maxRightSum = maxSumRec(a, center + 1, right);
		
		//左半部分最大值
		int maxLeftBoardSum = 0;
		int leftBoardSum = 0;
		for (int i = center; i >= left; i--) {
			leftBoardSum += a[i];
			if (leftBoardSum > maxLeftBoardSum)
				maxLeftBoardSum = leftBoardSum;
		}
		
		//右半部分最大值
		int maxRightBoardSum = 0;
		int RightBoardSum = 0;
		for (int i = center+1; i <= right; i++) {
			RightBoardSum += a[i];
			if (RightBoardSum > maxRightBoardSum)
				maxRightBoardSum = RightBoardSum;
		}
		
		return max3(maxLeftSum, maxRightSum, maxLeftBoardSum + maxRightBoardSum);
		
	}
	
	//返回三个数中最大的那个
	private static int max3(int a, int b, int c){
		return a >= b ? (a >= c ? a : c) : (b >= c ? b : c);
	}
	
	
	//算法四,最快的算法,运行时间O(N)
	//核心思想:任何负的子序列不可能是最优子序列的前缀!将子序列一步步推进,遇到负的前缀就把该前缀抛弃
	//该算法只对数据进行一次扫描,使得数据可以按顺序读入,在主存中不必存储数组的任何部分。在任意时刻,算法都能对
	//它已经读入的数据给出子序列的正确答案(其他算法不行)。具有这种特性的算法叫联机算法(on-line algorithm)
	public static int maxSubSum4(int[] a){
		int maxSum = 0;
		int thisSum = 0;
		for (int i=0; i<a.length; i++){
			thisSum += a[i];
			
			if (thisSum > maxSum)
				maxSum = thisSum;
			else if (thisSum < 0)
				thisSum = 0;
		}
		return maxSum;
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值