連續最大字段和問題


最大子段和問題描述

給定由 n 個整數(可能為負整數)組成的序列a1,a2,a3...an,求該數列中連續子段和最大!

    例如:當(a1,a2,a3,a4,a5)=(-2,11,-4,13,-5,-2)時,最大字段和為 20 (11 + (-4) + 13);

       以下例子都是以int data[6] = {-2,11,-4,13,-5,-2};    int n = 6;

 初始化數組: 

    //初始化數組
    private static Integer[] array = {-2, 11, -4, 13, -5, -2};

算法一:對所有滿足0<=i<=j<=n的(i,j)整數對進行迭代,對每個整數對,程序都要計算array[i...j]的總和,並檢驗該總和是否大於迄今為止的最大總和

這段代碼簡潔明了,便於理解,但是程序執行的速度很慢,時間復雜度為O(n^3)

  

  /**
     * 時間復雜度為 O(n^3)
     */
    public static Integer maxSum1() {
        int maxSum = 0;             //存儲最大子段和
        int tempSum;                //臨時存儲最大子段和
        for (int i = 0; i < array.length - 1; i++) {
            for (int j = i; j < array.length; j++) {
                tempSum = 0;
                for (int k = i; k <= j; k++) {
                    tempSum += array[k];
                    if (tempSum > maxSum) {
                        maxSum = tempSum;
                    }
                }
            }
        }
        return maxSum;
    }

  

算法二:對於算法一有一個明顯的缺點,大量的計算重復。大家可以注意到:

這段代碼簡潔明了,便於理解,相比算法一程序執行的速度較快,時間復雜度為O(n^2)

  注意:array[i...j]的總和與前面計算出的總和(array[i...j-1])密切相關,只需要在其基礎上累加即可,無需大量重復計算!

    /**
     * 時間復雜度為 O(n^2)
     */
    public static Integer maxSum2() {
        int maxSum = 0;             //存儲最大子段和
        int tempSum;                //臨時存儲最大子段和
        for (int i = 0; i < array.length - 1; i++) {
            tempSum = 0;
            for (int j = i; j < array.length; j++) {
                tempSum += array[j];
                if (tempSum > maxSum) {
                    maxSum = tempSum;
                }
            }
        }
        return maxSum;
    }

  

算法三:可以采用分治算法求解,采用二分法進行二分,然后進行遞歸求解,分別求出左邊連續子段和最大值,右邊連續子段和最大值,以及左邊和右邊連續子段和最大值之和,三者進行比較,從中選擇一個最大值進行返回!(這個值即就是當前划分的小區間中最大值)

  注意:這段代碼不太便於理解,但是程序相對於算法二執行的速度快,時間復雜度為O(n*logn)

  

  /**
     * 采用分治算法
     * 時間復雜度為 O(n*logN)
     */
    public static Integer maxSum3(int left, int right) {
        int maxSum = 0;
        if (left == right) {    //遞歸結束條件
            if (array[left] > 0) {
                maxSum = array[left];
            } else {
                maxSum = 0;
            }
            return maxSum;
        }

        int mid = (left + right) / 2;
        int leftMaxSum = maxSum3(left, mid);             //遞歸求解左部分最大值
        int rightMaxSum = maxSum3(mid + 1, right);  //遞歸求解右部分最大值

        //求解左邊最大值和右邊最大值之和
        int leftMax = 0;        //記錄左邊最大值
        int leftMaxTemp = 0;    //記錄左邊最大值的臨時變量
        for (int i = mid; i >= left; i--) {
            leftMaxTemp += array[i];
            if (leftMaxTemp > leftMax) {
                leftMax = leftMaxTemp;   //左邊最大值放在 leftMax
            }
        }
        int rightMax = 0;
        int rightMaxTemp = 0;
        for (int j = mid + 1; j <= right; j++) {
            rightMaxTemp += array[j];
            if (rightMaxTemp > rightMax) {
                rightMax = rightMaxTemp;  //右邊最大值放在 rightMax
            }
        }
        maxSum = leftMax + rightMax;//(左邊最大值和右邊最大值之和)計算第 3 種情況的最大子段和
        //比較(左邊最大值)和(右邊最大值)以及(兩邊最大值之和)進行比較,從中選擇一個最大值返回
        if (maxSum < leftMaxSum) {
            maxSum = leftMaxSum;
        }
        if (maxSum < rightMaxSum) {
            maxSum = rightMaxSum;
        }
        return maxSum;
    }

  

算法四:使用動態規划來求解 ,由data[]數組我們易知,當maxSumTemp > 0時,maxSumTemp = data[i] + maxSumTemp (越加越大),否則maxSumTemp = data[i](不然越加越小)

  這段代碼便於理解,但是程序相對於算法三執行的速度最快,時間復雜度為O(n)

  

    /**
     * 時間復雜度為 O(n)
     */
    public static Integer maxSum4() {
        int maxSum = array[0];
        int maxSumTemp = array[0];  //初始化

        for (int i = 1; i < array.length; i++) {
            if (maxSumTemp > 0) {           //最大值臨時變量只有大於零,才可能越加越大
                maxSumTemp += array[i];
            } else {                        //最大值臨時變量只有小於零,直接等於data[i],否則越加越小
                maxSumTemp = array[i];
            }
            if (maxSumTemp > maxSum) {      //判斷賦值
                maxSum = maxSumTemp;
            }
        }
        return maxSum;
    }

  

測試代碼:

 public static void main(String[] args) {
//        Integer maxSum = maxSum1();
//        Integer maxSum = maxSum2();
//        Integer maxSum = maxSum3(0, array.length - 1);
        Integer maxSum = maxSum4();
        System.out.println("maxSum = " + maxSum);
    }

  每天進步一點點,日記月累就會變成大牛!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM