1. 程式人生 > >演算法導論-最大子陣列問題-線性時間複雜度演算法分析與實現

演算法導論-最大子陣列問題-線性時間複雜度演算法分析與實現

之前寫了最大子陣列問題的分治法,今天把這個問題的線性時間複雜度的演算法寫出來。

這個方法在演算法導論最大子陣列問題的課後思考題裡面提出來了,只是說的不夠詳細。

思考題如下:使用如下思想為最大子陣列問題設計一個非遞迴的,線性時間複雜度的演算法。從陣列左邊界開始,由左至右處理,記錄到目前為止已經處理過的最大子陣列。若已知A[1...j]的最大子陣列,基於如下性質將解擴充套件為A[1...j+1]的最大子陣列:A[1...j+1]的最大子陣列要麼是A[1...j]的最大子陣列,要麼是某個子陣列A[i...j+1](1<=i<=j+1)。在已知A[1...j]的最大子陣列的情況下,可以線上性時間內找出形如A[i..j+1]的最大子陣列

思考題裡面已經把基本思想說的很清楚了,只是

“在已知A[1...j]的最大子陣列的情況下,可以線上性時間內找出形如A[i..j+1]的最大子陣列”

這句話裡面描述的方法沒有說出來.這裡我先把我的結論說出來,接下來再證明。 結論:在已知A[1...j]的最大子陣列的情況下(假設A[1..j]的最大子陣列是A[k...l]),找出A[i..j+1](1<=i<=j+1)的最大子陣列是如下三個子陣列中的最大和 1.A[k...l] 2.A[k...j+1] 3.max{A[x...j+1] | x為k + 2 至 j + 1} 也就是說,如果新的最大子陣列不是原來的最大子陣列,那麼新的最大子陣列的終點必然是j+1.這個是顯而易見的。 假設新的最大子陣列不是原來的,那麼起點是哪裡呢? 1.起點不可能小於k。因為如果小於k,那麼說明有A[x...j+1]>A[k...j+1](x<k),即存在A[x...k-1]>0,這顯然是不可能的。 2.起點不可能大於k小於等於l。因為如果那樣的話,說明有A[x...j+1]>A[k...j+1](k<x<=l),即A[k...x-1]<0,即最大子陣列的起點到它中間某個點小於0,這是不可能的。 3.起點不可能位於j + 1,因為j+1必然小於0。

所以演算法很容易就得出來了。

下面是這個問題的java實現。我沒做多少測試,有錯誤的話請指正。

public class FindMaxSubIntArray {
	public static class Result {
		int max;
		int start;
		int end;
	}

	public static Result findMaxSubIntArray(int[] a) {
		if (a == null || a.length < 1)
			return null;
		Result res = new Result();
		res.max = a[0];
		res.start = 0;
		res.end = 0;
		for (int i = 1; i < a.length; i++) {
			int max1 = a[i];//max1求的是上述三個子陣列中的第二個
			int max2 = a[i];//max2求的是上述有一個子陣列的第三個
			int max2_start = i;
			for (int j = i - 1; j > res.end; j--) {//這裡之所以求到res.end,沒有避開res.end+1,是想要讓max1加上res.end+1處的值
				max1 += a[j];
				if (max2 + a[j] > max2) {
					max2 += a[j];
					max2_start = j;
				}
			}
			max1 += res.max;
			if (max1 >= res.max && max1 >= max2) {
				res.max = max1;
				res.end = i;
			}
			if (max2 >= max1 && max2 >= res.max) {
				res.max = max2;
				res.start = max2_start;
				res.end = i;
			}
		}
		return res;
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int[] a = { 1,-2,4,-6,6,-2,-8 };
		Result res = findMaxSubIntArray(a);
		System.out.println(res.start + " " + res.end + " " + res.max);
	}

}