• 算法 蓄水问题


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

    例【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));
        }
  • 相关阅读:
    浅析Python中bytes和str区别
    Python面对对象相关知识总结
    Django实现微信公众号简单自动回复
    阿里云部署django实现公网访问
    JDBC学习笔记(1)——JDBC概述
    Java单元测试初体验(JUnit4)
    Java设计模式系列之动态代理模式(转载)
    Java设计模式系列之责任链模式
    Java设计模式系列之观察者模式
    局部内部类和匿名内部类的对比
  • 原文地址:https://www.cnblogs.com/unknown6248/p/14578511.html
Copyright © 2020-2023  润新知