求最大子段和問題

求最大子段和的問題是比較經典的算法,能夠由簡單的算法到複雜的算法逐步遞進。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)效率

相關文章
相關標籤/搜索