算法-leetcode-每日一题-求最大子数组

分析:该题是一道经典的题,但是很多人理解不了,我在此处进行了总结,大家按我的思路看下去,肯定能理解。

  1. 使用蛮力法。最外循环为第i个数,第二循环从i开始一直到数组尾j,最内循环则计算i到j子数组的和。

    public static int maxSubArray(int arr[]) {
        int n = arr.length;
        int ThisSum = 0, MaxSum = 0;
        for(int i=0; i<n; i++) {    //从0开始循环
            for(int j=i; j<n; j++) {//从当前位循环到最后一位
                ThisSum = 0;
                for(int k=i; k<j; k++) {//计算i到j的子序列和
                    ThisSum += arr[k];
                }
                if(ThisSum > MaxSum) { MaxSum = ThisSum; }
            }
        }
        return MaxSum;
    }
    
  2. 该方式重复的计算了i到j之间值,重点在于如何减少重复的计算,在最内的k循环中,可以通过Sum[I, j] = Sum[I, j-1]+arr[j],这样就能避免重复的计算。

     public static int maxSubArray(int arr[]) {
         int size = arr.length;
         int maxSum = Integer.MAX_VALUE;
         for(int i=0; i<size; i++) {//同样还是两个循环,要计算的还是i到j序列的和
             int sum = 0;//不同的是sum是递增的,即在j++的过程中,前面的sum是不变的
             for(int j=i; j<size; j++) {
                 sum += arr[j];
                 if(sum > maxSum) { maxSum = sum; }//这个判断是获取子序列的关键
             }
         }
         return maxSum;
     }
    
  3. 注意上面两个方案的叠进顺序,和对第二个解决方案的理解。动态优化依然是减少重复的运算。在上面的算法中,只消除了固定i下j的重复计算,但当i变化时,sum的部分值依然是重复的。那如何分解问题?若已知A[1, j]的最大子数组,那A[1, j+1]的最大子数组等于求解最后一个元素arr[n-1]与最大子数组的关系:①最大子数组包含arr[n-1],即以arr[n-1]结尾;②arr[n-1]单独构成最大子数组;③最大子数组不包含arr[n-1]。三种可能写为All[ i - 1] = max{arr[ i - 1 ], End[ i - 1 ], All[ i - 2 ]},三个选项分为对应①②③。End[i]是包含第i值的最大子数组,All[i]是当前最大子数组。

     public static int maxSubArray(int arr[]) {
         int n = arr.length;
         int End[] = new int[n];//End[i]表示包含当前值的最大子数组值
         int All[] = new int[n];//All[i]表示当前全局最大子数组值
         End[0] = All[0] = arr[0];//一开始全为arr[0]
         for(int i=1; i<n; i++) {//End是个辅助数组,用于比较①② All则在比较③
             End[i] = max(End[i-1] + arr[i], arr[i]);//比较当前值是否比包含当前值的序列大
             All[i] = max(End[i], All[i-1]);//比较当前值序列是否比不包含当前值序列大
         }
         return All[n-1];
     }
    
  4. 上面每次只用到End[n-1]和All[n-1],这样只需要定义两个变量即可。

       public static int maxSubArray4(int arr[]) {
            int n = arr.length;
            int nAll = arr[0];
            int nEnd = arr[0];
            for(int i=1; i<n; i++) {
                nEnd = max(nEnd + arr[i], arr[i]);//比较当前值是否比包含当前值的序列大
                nAll = max(nEnd, nAll);//比较当前值序列是否比不包含当前值序列大
            }
            return nAll;
        }
    

猜你喜欢

转载自blog.csdn.net/wujingchangye/article/details/88633681