演算法導論-最大子陣列問題-線性時間複雜度演算法分析與實現
阿新 • • 發佈:2019-01-06
之前寫了最大子陣列問題的分治法,今天把這個問題的線性時間複雜度的演算法寫出來。
這個方法在演算法導論最大子陣列問題的課後思考題裡面提出來了,只是說的不夠詳細。
思考題如下:使用如下思想為最大子陣列問題設計一個非遞迴的,線性時間複雜度的演算法。從陣列左邊界開始,由左至右處理,記錄到目前為止已經處理過的最大子陣列。若已知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); } }