算法 蓄水问题

问题:    
  给定一个数组,想象成一个桶。问最多能装多少水?

例【1,5,3,6】 最多装2格水 O O ~ O O ~ O O O O O O O O O O O


解题思路:
  我们把每一列当成一块板,根据分析,第一块板和最后一块板一定不能蓄水,所以问题变成了所有板所能蓄水最大值的总和。先明确这个思路,之后再想办法。

那么如何确定当前板可以蓄多少水呢?和它左右两边最长的板有关系。等于左右两边最长板的较小者减去当前板的长度和0取最大值。
表示为:
    当前板蓄水量 = math.max(0, math.min(左最长板,右最长板) - 当前)
    第一、最后一块板蓄水量 = 0

方法一:O(n^2)
  简单暴力,挨个遍历每一块板,求出左右最大值,根据上面公式进行计算。不做演示

方法二:O(n)
  根据方法一可知,时间复杂度主要在寻找每一块板的左右最大值。那么优化的方向就是使用O(n)复杂度获得每一块板的左右最大值。
怎么做呢?借助辅助数组。
例如【1,5,3,6】,则左边最大值数组为【1,5,5,6】,右边最大值数组为【6,6,6,6】
三个数组分别表示当前板长度,当前板的左边板最大长度、当前板的右边板最大长度。

    public static int shui(int[] param) {
        if(param == null || param.length < 2) return 0;
        
        int[] L = new int[param.length];
        int[] R = new int[param.length];
    
        for(int i=1;i<param.length;i++) {
            L[i] = Math.max(param[i], param[i - 1]);
        }
        for(int i=param.length - 2;i>0;i--) {
            R[i] = Math.max(param[i], param[i + 1]);
        }
        
        int shui = 0;
        for(int i = 1; i<param.length-1;i++)
        {
            shui += Math.max(0, Math.min(L[i], R[i]) - param[i]);
        }
        return shui;
    }
方法三:O(n)
  方法二空间复杂度太大,所以还有优化空间。
可以从两边同时进行判断,并且保存当前左右最大值。
如果左边最大值小于右边最大值,那么左边的当前板所能蓄水量就可确定 = math.max(0, 左最大值 - 当前)并且当前索引++,标记左边最大值 = math.max(左最大值,当前板)。
如果右边最大值小于左边最大值,那么右边的当前板所能蓄水量就可确定 =
math.max(0, 右最大值 - 当前)并且当前索引--,标记右边最大值 = math.max(右最大值,当前板)。
如果相等,随便归属一边,或两边一起计算。

    /*
     * 给定一个数组,想象成一个桶。问最多能装多少水
     * 例【1,5,3,6】   最多装2格水
     *          O
     *    O  ~  O
     *    O  ~  O
     *    O  O  O 
     *    O  O  O
     * O  O  O  O
     * 
     */
    
    public static int shui(int[] param) {
        if(param == null || param.length < 2) return 0;
        
        int L = 1, R = param.length-2, shui = 0;
        int lmax = param[0], rmax = param[R + 1];
        while(L<=R) {
            if(lmax <= rmax) {
                shui += Math.max(0, lmax - param[L]);
                lmax = Math.max(lmax, param[L++]);
            }else {
                shui += Math.max(0, rmax - param[R]);
                rmax = Math.max(rmax, param[R--]);
            }
        }
        return shui;
    }
    
    public static void main(String[] args) {
        int[] a = {2,1,3,5,2,6};
        System.out.println(shui(a));
    }

 

posted @ 2021-03-25 19:17  无名之士  阅读(285)  评论(0编辑  收藏  举报