Algorithms(一)---最大子數組和問題

1.You are given an array containing both positive and negative integers and required to find the sub-array with the largest sum (O(N) a la KBL). Write a routine for the above.

題目描述:
輸入一個整形數組,數組裏有正數也有負數。
數組中連續的一個或多個整數組成一個子數組,每個子數組都有一個和。
求所有子數組的和的最大值。要求時間複雜度爲O(n)。

思想:
設sum(i)爲以第i個元素結尾且和爲最大的連續子數組。假設對於元素i,所有以它前面的元素結尾的子數組的長度都已經求得,那麼以第i個元素結尾且和最大的連續子數組實際上,要麼是以第i-1個元素結尾且和最大的連續子數組加上這個元素,要麼是隻包含第i個元素,即sum[i] = max(sum(i-1) + a[i], a[i])。可以通過判斷sum(i-1) + a[i]是否大於a[i]來做選擇,而這實際上等價於判斷sum(i-1)是否大於0。

    public static int getMax(int[] arr) {

        if(0 == arr.length || null == arr) {
            System.out.println("數組不合法");
            return Integer.MIN_VALUE;
        }

        int max = arr[0], sum = arr[0];

        for(int i=1; i<arr.length; i++) {
            if(sum > 0) {
                sum += arr[i];
            } else {
                sum = arr[i];
            }

            if(sum > max) {
                max = sum;
            }
        }

        return max;
    }

現在假設數組首尾相接,就是組成了一個環狀連續數組,求最大子數組之和。
如果數組是首尾相鄰的,可以分成兩種情況來討論:

(1) 如果最大和子數組沒有跨越首尾,則可以用原問題的解法來求解

(2)如果最大和子數組跨越首尾,則可以繼續分兩種情況討論:
如果數組元素全部爲正,則所有元素之和就是最大值
如果數組中有負數,則最大和子數組必然不包括某些元素,而不被包括的元素中必然有最小和子數組,這樣我們就可以先查找最小和子數組的最後一個點,並以下一個點爲起點,利用(1)的方法循環遍歷一遍數組,就可以得到最大和子數組了
這裏寫圖片描述
取得最小值的索引:

   public static int getMinIndex(int[] arr) {

        if(0 == arr.length || null == arr) {
            System.out.println("數組不合法");
            return Integer.MIN_VALUE;
        }

        int min = arr[0], sum = arr[0], minIndex = 0, i;

        for(i=1; i<arr.length; i++) {
            if(sum < 0) {
                sum += arr[i];
            } else {
                sum = arr[i];
            }

            if(sum < min) {
                min = sum;
                minIndex = i;
            }
        }

        return minIndex;
    }

取環狀數組最大值:

   public static int getMaxConnect(int[] arr) {

        int minIndex = getMinIndex(arr);
        if(Integer.MIN_VALUE == minIndex) {
            return minIndex;
        }

        int max = arr[(minIndex+1) % arr.length], sum = arr[(minIndex+1) % arr.length];
        for(int i=2; i<arr.length; i++) {
            if(sum > 0) {
                sum += arr[(minIndex+i) % arr.length];
            } else {
                sum = arr[(minIndex+i) % arr.length];
            }

            if(sum > max) {
                max = sum;
            }
        }
        return max;
    }

測試程序:
因爲上面考慮的是跨過首尾的,如果沒有跨過首尾我們就需要用最開始說的按照不是環的連續數組來求最大值,所以對於一個我們並不知道是否最大和子數組跨過首尾的時候我們需要採取兩種方法來分別求最大值,最終取兩個中較大的值即可。

    public static void main(String[] args) {
        int[] arr = {1,-4,8,-2,-3,12,4,6,3,-1,-2};

        int noConnect = getMaxSum(arr); //求非環行數組的最大值
        int connect = getMaxConnect(arr);   //求環形數組的最大值

        //輸出較大的值
         System.out.println(noConnect > connect? noConnect : connect);
    }

完整代碼:

public class MaxSubArr {
    public static void main(String[] args) {
        int[] arr = {1,-4,8,-2,-3,12,4,6,3,-1,-2};

        int noConnect = getMaxSum(arr); //求非環行數組的最大值
        int connect = getMaxConnect(arr);   //求環形數組的最大值

        //輸出較大的值
         System.out.println(noConnect > connect? noConnect : connect);
    }

    public static int getMaxSum(int[] arr) {
        if(0 == arr.length || null == arr) {
            System.out.println("數組不合法");
            return Integer.MIN_VALUE;
        }
        int max = arr[0];
        int sum = arr[0] > 0 ? arr[0] : 0;

        for(int i=1; i<arr.length; i++) {
            if(sum + arr[i] > 0) {
                sum += arr[i];
                max = max > sum ? max : sum;
            } else {
                sum = 0;
                max = max > arr[i] ? max : arr[i];
            }
        }
        return max;
    }

    public static int getMax(int[] arr) {

        if(0 == arr.length || null == arr) {
            System.out.println("數組不合法");
            return Integer.MIN_VALUE;
        }

        int max = arr[0], sum = arr[0];

        for(int i=1; i<arr.length; i++) {
            if(sum > 0) {
                sum += arr[i];
            } else {
                sum = arr[i];
            }

            if(sum > max) {
                max = sum;
            }
        }

        return max;
    }

    public static int getMinIndex(int[] arr) {

        if(0 == arr.length || null == arr) {
            System.out.println("數組不合法");
            return Integer.MIN_VALUE;
        }

        int min = arr[0], sum = arr[0], minIndex = 0, i;

        for(i=1; i<arr.length; i++) {
            if(sum < 0) {
                sum += arr[i];
            } else {
                sum = arr[i];
            }

            if(sum < min) {
                min = sum;
                minIndex = i;
            }
        }

        return minIndex;
    }

    public static int getMaxConnect(int[] arr) {

        int minIndex = getMinIndex(arr);
        if(Integer.MIN_VALUE == minIndex) {
            return minIndex;
        }

        int max = arr[(minIndex+1) % arr.length], sum = arr[(minIndex+1) % arr.length];
        for(int i=2; i<arr.length; i++) {
            if(sum > 0) {
                sum += arr[(minIndex+i) % arr.length];
            } else {
                sum = arr[(minIndex+i) % arr.length];
            }

            if(sum > max) {
                max = sum;
            }
        }
        return max;
    }
}
發佈了74 篇原創文章 · 獲贊 3 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章