求解最大子数组

求解最大子数组

  • 问题描述,神马是最大子数组

    假定我们一个已知的数组为:

    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 + "]";
            }   
        }   
    }

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