搜索算法-求解最大子數組

問題定義: 假設在100, 113, 110, 85, 105, 102, 86, 63, 81, 101, 94, 106, 101, 79, 94, 90 , 97 這樣一組數據中,它的一個實際背景是,每個值反應的是每天的股票價格,我們需要求出哪天買進股票,哪天賣出股票,得到的收益最大。

解法: 

1.使用暴力求解

我們需要遍歷每一種可能的買進和賣出日期組合,也就是窮盡每一種可能的子數組。也就是n中任意去2個座標的組合數。顯然它是O(n^2)量級的。

2.使用遞歸分治的思想 

2.1轉化思想 

把問題 轉化爲最大子數組問題 先對數組進行轉化, 轉化爲收益數組

13    -3    -25    20     -3      -16      -23     18     20     -7     12     -5     -22    15    -4      第i個值,表示第i天的價格 - 第i-1天的價格

2.2 分類討論

最大子數組出現的可能情況來源於3個, 我們不妨把數組進行等分  min = (low + high ) / 2;

1.情況一, 最大子數組來源於 左半數組

2. 情況二,最大子數組來源於 右半數組

3. 情況三, 最大數組穿過數組中間。

2.3  遞歸迭代

本模式滿足遞歸迭代模式, 運用遞歸的思想 可以得到 maxSubArry(A)  = Max( maxSubArray(A-left), maxSubArray(A-right), maxCrosSubArrray(A));

基於這樣的求解思想,給出對應的程序實現

//該類用於最大子數組
class SubArray{
	int sum;
	int low;
	int high;
	public SubArray(int sum, int low, int high){
		this.sum = sum;
		this.low = low;
		this.high = high;
	}
}
	//最大子數組的搜索
	public static SubArray findMaxCroSubArray(int[] array, int low, int mid, int high){
		//算法要求是尋找誇區間的最大子數組
		//思想 遍歷法, 化歸爲求最大的連續和,  對稱性, 左右對稱
		//先求左半邊
		int leftSum = Integer.MIN_VALUE;
		int sum = 0;
		int leftIndex = mid;
		for(int i = mid; i>=low; i--){
			sum += array[i];
			if(sum > leftSum){
				leftSum = sum;
				leftIndex = i;
			}
		}
		//得到了左半邊的最大連續和 以及 對應的下標
		
		int rightSum = Integer.MIN_VALUE;
		int rightIndex = mid+1;
		sum = 0;
		for(int i = mid+1; i<=high; i++){
			sum += array[i];
			if(sum > rightSum){
				rightSum = sum;
				rightIndex = i;
			}
		}
		SubArray resultSubArray = new SubArray(leftSum + rightSum, leftIndex, rightIndex);
		return resultSubArray;
	}
	
	//求連續數組
	public static SubArray findMaxSubArray(int[] array, int low, int high){
		//思想, 分類整合的思想 遞歸的思想
		//分情況, 1.遞歸的求左半邊的最大連續子數組  2.遞歸的求右半邊的最大連續子數組  3.求最大連續跨區間數組   然後取三者值
		//遞歸的終止條件是 如果low==high 那麼 返回array[low] 即可
		if(low == high){
			SubArray resultSubArray = new SubArray(array[low], low, high);
			return resultSubArray;
		}
		int mid = (low + high) / 2;
		SubArray leftSubArray = findMaxSubArray(array, low, mid);
		SubArray rightSubArray = findMaxSubArray(array, mid+1, high);
		SubArray croSubArray  = findMaxCroSubArray(array, low, mid, high);
		
		System.out.print("array:");
		for(int i =low; i<=high; i++){
			System.out.print(array[i]+" ");
		}
		//13 -3 -25 20 -3 -16 -23 18 20 -7 12 -5 -22 15 -4 7 
		System.out.println();
		if(leftSubArray.sum >= rightSubArray.sum && leftSubArray.sum >= croSubArray.sum){
			//此時最大是leftSubArray
			System.out.println(leftSubArray.sum+", "+leftSubArray.low+", "+leftSubArray.high);
			return leftSubArray;
		}else if(rightSubArray.sum >= leftSubArray.sum && rightSubArray.sum >= croSubArray.sum){
			System.out.println(rightSubArray.sum+", "+rightSubArray.low+", "+rightSubArray.high);
			return rightSubArray;
		}else {
			System.out.println(croSubArray.sum+", "+croSubArray.low+", "+croSubArray.high);
			return croSubArray;
		}
	}
下面給出遞歸的構造結果過程:

array:13 -3
13, 0, 0
array:-25 20
20, 3, 3
array:13 -3 -25 20
20, 3, 3
array:-3 -16
-3, 4, 4
array:-23 18
18, 7, 7
array:-3 -16 -23 18
18, 7, 7
array:13 -3 -25 20 -3 -16 -23 18
20, 3, 3
array:20 -7
20, 8, 8
array:12 -5
12, 10, 10
array:20 -7 12 -5
25, 8, 10
array:-22 15
15, 13, 13
array:-4 7
7, 15, 15
array:-22 15 -4 7
18, 13, 15
array:20 -7 12 -5 -22 15 -4 7
25, 8, 10
array:13 -3 -25 20 -3 -16 -23 18 20 -7 12 -5 -22 15 -4 7
43, 7, 10
43
18 20 -7 12


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章