求解最大子數組

求解最大子數組

  • 問題描述,神馬是最大子數組

    假定我們一個已知的數組爲:

    int numbers[]={1,2,6,3,-5,-7,1,-6,8};

    現在我們需要求解其中某幾個數之和最大的一段子數組,如果不考慮方法的複雜性,首先我們可以考慮暴力求解,即將所有可能的組合進行排列組合。那麼我們可以得到n*(n-1)/2(不考慮順序的排列組合)種可能,其複雜度爲O(n^2)。

  • 爲求得更好的解題思路,我們可以考慮使用分治法。

    1. 首先我們將數組按照中點分成兩個部分
      這裏寫圖片描述
      這樣求解最大子數組的問題就變成了求左邊部分,右邊部分,跨過中間部分的最大子數組,其中求解左邊和右邊與求解整個數組的最大子數組邏輯相同。關鍵在於如何求解中間部分的最大子數組。

    2. 對於求解中間部分的最大子數組,由於該數組會經過中點,所以可以分解爲兩部分,分別爲從middle向左出發,到左邊某個index的最大值以及從middle出發,到右邊某個index的最大值。將兩個部分的最大值相加即可得到跨過中點的最大子數組,其時間複雜度爲O(n);其基本實現如下:

      public static Model findCrossMiddle(int leftIndex,int middle,int rightIndex){
          int leftSum=Integer.MIN_VALUE;
          int leftRes=middle;
          int rightSum=Integer.MIN_VALUE;
          int rightRes=middle+1;
          int sum=0;
          for(int i=middle;i>=leftIndex;i--){
              sum+=numbers[i];
              if(sum>leftSum){
                  leftSum=sum;
                  leftRes=i;
              }
          }     //從middle向左出發,到左邊某個index的最大值,並記錄下標
          sum=0;
          for(int j=middle+1;j<=rightIndex;j++){
              sum+=numbers[j];
              if(sum>rightSum){
                  rightSum=sum;
                  rightRes=j;
              }
          }   //從middle向左出發,到左邊某個index的最大值,並記錄下標
          return new Model(leftRes,rightRes,(leftSum+rightSum));
      }
  • 實現算法

    分析完基本實現思路,很自然就想到通過遞歸完成算法,要想通過遞歸,就要先知道算法的結束條件。在這裏就是當劃分的子數組只有一個元素時,則直接返回。在每次遞歸的時候,比較左中右三段中的哪個最大子數組最大,並返回表示該段中的最大子數組。

    其完整實現代碼如下:

    public class MaxChildArray {
    
        private static int numbers[]={1,2,6,3,1,8};
        public static void main(String[] args) {
            Model res=findMaxChildArray(0,numbers.length-1);
            System.out.println(res);
        }
    
        //查找最大子數組的遞歸方法
        public static Model findMaxChildArray(int leftIndex,int rightIndex){
            if(leftIndex==rightIndex){
                return new Model(leftIndex,rightIndex,numbers[leftIndex]);
            }
            else{
                int middle=((leftIndex+rightIndex)/2);
                Model modelLeft=findMaxChildArray(leftIndex,middle);
                Model modelRight=findMaxChildArray(middle+1, rightIndex);
                Model acrossModel=findCrossMiddle(leftIndex,middle,rightIndex);
                if(modelLeft.getSum()>=modelRight.getSum()&&modelLeft.getSum()>=acrossModel.getSum()){
                    return modelLeft;
                }
                else if(modelRight.getSum()>=modelLeft.getSum()&&modelRight.getSum()>=acrossModel.getSum()){
                    return modelRight;
                }
                else{
                    return acrossModel;
                }
            }
        }
    
        //查找經過中點的最大子數組
        public static Model findCrossMiddle(int leftIndex,int middle,int rightIndex){
            int leftSum=Integer.MIN_VALUE;
            int leftRes=middle;
            int rightSum=Integer.MIN_VALUE;
            int rightRes=middle+1;
            int sum=0;
            for(int i=middle;i>=leftIndex;i--){
                sum+=numbers[i];
                if(sum>leftSum){
                    leftSum=sum;
                    leftRes=i;
                }
            }
            sum=0;
            for(int j=middle+1;j<=rightIndex;j++){
                sum+=numbers[j];
                if(sum>rightSum){
                    rightSum=sum;
                    rightRes=j;
                }
            }
            return new Model(leftRes,rightRes,(leftSum+rightSum));
        }
    
    
    
    
    
        //定義數據模型
        public static class Model{
            private int leftIndex;
            private int rightIndex;
            private int sum;
            public Model(int leftIndex, int rightIndex, int sum) {
                super();
                this.leftIndex = leftIndex;
                this.rightIndex = rightIndex;
                this.sum = sum;
            }
            public int getLeftIndex() {
                return leftIndex;
            }
            public void setLeftIndex(int leftIndex) {
                this.leftIndex = leftIndex;
            }
            public int getRightIndex() {
                return rightIndex;
            }
            public void setRightIndex(int rightIndex) {
                this.rightIndex = rightIndex;
            }
            public int getSum() {
                return sum;
            }
            public void setSum(int sum) {
                this.sum = sum;
            }
            @Override
            public String toString() {
                return "Model [leftIndex=" + leftIndex + ", rightIndex=" + rightIndex + ", sum=" + sum + "]";
            }   
        }   
    }

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章