求最大子段和的問題是比較經典的算法,能夠由簡單的算法到複雜的算法逐步遞進。css
給定序列a [1],a [2],a [3] …… a [n],您的工做是計算子序列的最大和。
例如,給定(6,-1,5, 4,-7),此序列中的最大和爲6 +(-1)+ 5 + 4 = 14。
給定(0,6,-1,1,-6,7,-5),最大和爲7。算法
把全部的狀況都算出來,取出最大值,這種算法的時間複雜度爲O(n^3),i從數組頭部到尾部,j從i到數組尾部,k從i到j。數組
public int MaxSum(int[] array) {
int currentSum = 0;
int sum = 0;
for (int i = 0; i < array.length; i++) {
for (int j = i; j < array.length; j++) {
currentSum = 0;
for (int k = i; k <= j; k++) {
currentSum = currentSum + array[k];
}
if (currentSum > sum) {
sum = currentSum;
}
}
}
return sum;
}
若是看不懂上面的算法,能夠在紙上寫出來,用了三層循環遍歷計算全部的結果,在上述代碼中其實有好多的計算是重複的,例如:當i=0,j=3時要計算a[0]+a[1]+a[2]+a[3],當j=4時,要計算a[0]+a[1]+a[2]+a[3]+a[4],顯然這個計算有一部分是多餘的。第一層循環從0到array的長度-1,第2、三層循環主要負責計算子段的和,把每次計算的子段和和存到currentSum變量中,與sum進行比較(sum存儲的是最終的最大子段和),若是大則進行交換。經過分析上面的代碼有大量的重複計算,效率不高。markdown
分析算法一發現有大量的重複計算,避免這些重複計算能夠提升不少的效率,咱們發現算法一中的一個循環能夠去掉。spa
public int MaxSum1(int[] array) {
int currentSum = 0;
int sum = 0;
for (int i = 0; i < array.length; i++) {
currentSum = 0;
for (int j = i; j < array.length; j++) {
currentSum += array[j];
if (currentSum > sum) {
sum = currentSum;
}
}
}
return sum;
}
雖然算法二較算法一減小了一層循環,時間複雜度能夠減小到O(n^2)。不須要k,在找到j的時候就將子段和記錄下來。可是依然存在重複的計算,還不是最優的。code
目標減小重複計算的次數,儘量避免重複的計算過程,依然是減小循環io
public int MaxSum2(int[] array) {
int currentSum = 0;
int sum = 0;
for (int i = 0; i < array.length; i++) {
currentSum += array[i];
if (currentSum > sum) {
sum = currentSum;
}
if (currentSum < 0) {
currentSum = 0;
}
}
return sum;
}
上面的算法過程是循環遍歷整個數組,接着計算每一個子段的和,判斷這個子段和,第一次循環若是大於0則賦值給sum,小於0不計算當前元素,接着第二次循環加上上次循環中計算出的子段和……
下面是動態規劃算法另外一種實現形式:class
public int MaxSum3(int[] array) {
int num = array.length;
int sum = 0;
int y = 0;
for (int i = 0; i < num; i++) {
if (y > 0) {
y += array[i];
} else {
y = array[i];
}
if (y > sum) {
sum = y;
}
}
return sum;
}
因爲只有一層循環,時間複雜度降爲O(n)效率