經典最大子序列和問題

//最大子序列和問題的四種算法
//注意以下算法只是求出最大的和,並沒有找出對應的子序列
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;
	}
}

發佈了24 篇原創文章 · 獲贊 19 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章