第四章、分治策略 -- 最大子数组问题

最大子数组问题

最大子数组问题是寻找数组中和最大的非空连续子数组,这样的连续子数组为最大子数组。

使用分治策略的求解方法

首先是分解问题,把数组 A [ l o w … h i g h ] A[low…high] A[lowhigh]划分成两个规模尽量相等的子数组 A [ l o w . . . m i d ] A[low...mid] A[low...mid] A [ m i d + 1... h i g h ] A[mid+1...high] A[mid+1...high]。那么最大子数组 A [ i . . j ] A[i..j] A[i..j]必定在 A [ l o w . . . m i d ] A[low...mid] A[low...mid]之间、 A [ m i d + 1... h i g h ] A[mid+1...high] A[mid+1...high]之间或者跨越中点,如果是在 A [ l o w . . . m i d ] A[low...mid] A[low...mid]之间或者 A [ m i d + 1... h i g h ] A[mid+1...high] A[mid+1...high]之间,那么就是原问题的子问题,所以剩下的问题就是求解跨越中点的最大子数组。

求跨越中点的最大子数组的方法:

	private static Map findMaxCrossingSubArray(int[] a, int low, int mid, int high) {
		int leftSum = a[mid];
		int sum = 0;
		int leftIndex = 0;
		for (int i = mid; i >= low; i--) {
			sum += a[i];
			if (sum >= leftSum) {
				leftSum = sum;
				leftIndex = i;
			}
		}
		sum = 0;
		int rightSum = a[mid+1];
		int rightIndex = 0;
		for (int i = mid+1; i <= high; i++) {
			sum += a[i];
			if (sum >= rightSum) {
				rightSum = sum;
				rightIndex = i;
			}
		}
		return buildResult(leftIndex, rightIndex, leftSum + rightSum);
	}
	
	private static Map buildResult(int startIndex, int endIndex, int sum) {
		Map result = new HashMap<>();
		result.put("startIndex", startIndex);
		result.put("endIndex", endIndex);
		result.put("sum", sum);
		return result;
	}

最后求最大子数组:

	private static Map findMaximumSubArray(int[] a, int low, int high) {
		if (low == high) {
			return buildResult(low, high, a[low]);
		} else {
			int mid = (low + high) >> 1;
			Map leftResult = findMaximumSubArray(a, low, mid);
			Map rightResult = findMaximumSubArray(a, mid + 1, high);
			Map crossResult = findMaxCrossingSubArray(a, low, mid, high);
			if (leftResult.get("sum") >= rightResult.get("sum") 
					&& leftResult.get("sum") >= crossResult.get("sum")) {
				return leftResult;
			} else if (rightResult.get("sum") >= leftResult.get("sum") 
					&& rightResult.get("sum") >= crossResult.get("sum")) {
				return rightResult;
			} else {
				return crossResult;
			}
		}
	}
	
	public static int[] findMaximumSubArray(int[] a) {
		Map result = findMaximumSubArray(a, 0, a.length - 1);
		return bulidArrayFromSrc(a, result.get("startIndex"),
			result.get("endIndex") - result.get("startIndex") + 1);
	}
	
	private static int[] bulidArrayFromSrc(int[] src, int startIndex, int length) {
		int[] result = new int[length];
		System.arraycopy(src, startIndex, result, 0, length);
		return result;
	}

该算法复杂度为 Θ ( n l g n ) \Theta(nlgn) Θ(nlgn)

线性时间的解法:

	public static int[] findMaximumSubArray2(int[] a) {
		if (a == null ) {
			throw new IllegalArgumentException("array must not null");
		}

		if (a.length == 0) {
			return null;
		}

		int startIndex = 0;
		int endIndex = 0;
		int reStart = -1;
		int max = a[0];
		int sum = 0;
		
		for (int i = 0; i < a.length; i++) {
			if (sum <= 0) {
				sum = a[i];
				reStart = i;
			} else {
				sum += a[i];
				
			}
			
			if (max < sum) {
				if (reStart != -1) {
					startIndex = reStart;
				}
				endIndex = i;
				max = sum;
			}
		}
		
		return bulidArrayFromSrc(a, startIndex, endIndex - startIndex + 1);
	}

你可能感兴趣的:(算法导论笔记)