• 算法图解——截留雨水( Trapping Rain Water)


    1. 题目描述

    Given n non-negative integers representing an elevation map where the width of each bar is 1, compute how much water it can trap after raining.

    为了方便理解,还是决定给大家翻译一下吧:

    给定n个非负整数,表示一个高度图,其中每个条形的宽度为1,计算从上往下下雨后它能集聚多少水。

    2. 示例

    示例1:

    Input: height = [0,1,0,2,1,0,1,3,2,1,2,1]
    Output: 6
    Explanation: The above elevation map (black section) is represented by array [0,1,0,2,1,0,1,3,2,1,2,1]. In this case, 6 units of rain water (blue section) are being trapped.

    什么意思呢?通过一个图我们就明白了,大概是这样:

     图中黑色的表示高度数组值,蓝色的表示集聚的雨水,一个方格代表1,故集聚了6个单位的雨水。

    示例2:

    同理:

    Input: height = [4,2,0,3,2,5]
    Output: 9

    图示这样:黄色为高度值,蓝色为雨水量。

    3. 输入要求

    • n == height.length
    • 0 <= n <= 3 * 104
    • 0 <= height[i] <= 105
    • 复杂度要求为O(n)

    4. 题目解析

    有人看到示例2会觉得,咦?是不是可以用面积来计算呢?

    但是又看到示例1的时候,会发现,面积并不是特别方便,因为,并不是中间所有的间隙都能够储存雨水。只有形成“凹”字型时,才能够集聚雨水。

    所以我们只能另辟蹊径。

    我们使用多指针法:假设数组为A[length];

    因为要求复杂度为O(N),故需要遍历一遍,故分别设置 left 和 right 两个指针。并使用while(left<right)来控制循环。

     其实,我们从示例1中这张图就可以看出:如果我们设置一个中间变量 Max 用来表示当前遇到的最大值,那么,在遍历高度数组A时,下一个数组值 A[left] 如果比 Max 小,则用Max减去该值就是此处可以存储的雨水量,且更新 left 继续遍历;如果该值 A[left] 大于 Max 时,那么 Max 更新为 A[left],且更新 left 指针,继续遍历。

    代码如:

    if(A[left]>=Max){
        Max = A[left];
    }else{
        res += (Max-A[left]);
    }
    left++;

     但是,我们这里要考虑的不仅仅是一面,因为会存在这样一种情况就是:

    输入为:[5,0,0,0,0,0]

    输出不是5*5=25,而是0,因为右侧没有高度,形成不了“凹”字型。

    所以我们应该还需要设置右侧最大值,为了与前面的最大值Max做区分,我们将前述的最大值 Max 改为 leftMax,此处右侧最大高度值为rightMax,这样我们就可以从两侧向中间收缩。

    判断到底当前步是从左还是从右收缩,需要依据 A[left] 和 A[right] 的值的大小——【谁小谁收缩】

    右侧代码为:

    if(A[right]>=rightMax){
        rightMax = A[right];
    }else{
        res += (Max-A[right]);
    }
    right--;

    故:整体过程就是:

    public  int trap(int[] A){
        int res = 0;
        int left = 0;
        int right = A.length-1;
        int leftMax = 0;  //左侧海拔最高值
        int rightMax = 0;   //右侧海拔最高值
    
        while(left<right){
            if(A[left]<=A[right]){     //左右两侧谁矮收缩谁
                if(A[left]>=leftMax){
                    leftMax = A[left];   //更新左侧海拔最高值
                }else{
                    res += (leftMax-A[left]);   //累计雨水量
                }
                left++;   //更新左侧指针
            }else{
                if(A[right]>=rightMax){
                    rightMax = A[right];     //更新右侧海拔最高值
                }else{
                    res += (rightMax-A[right]);    //累计雨水量
                }
                right--;     //更新右侧指针
            }
        }
    }

    参考及致谢:

    1、LeetCode Top 100 高频算法题42. Trapping Rain Water:来自《菜鸟名企梦》公众号,希望大家关注一波,谢谢~~~

    Over...

  • 相关阅读:
    appium 启动失败解决方案
    appium for windows 环境搭建
    HttpClient 4 使用方法的几个例子(代理,StringEntity字符串数据,文件上传)(转载)
    下拉框和单选框复选框的选中的值
    js刷新父页面的方法
    克隆虚拟机ip修改后没改变的原因
    二进制转换与此平台,VMware Workstation不,Workstation 不可恢复,此虚拟环境中的长模式
    在虚拟机(VMware)中安装Linux CentOS 6.4系统(图解) 转
    sql语句常用的函数总结
    java.lang.OutOfMemoryError: Java heap space 。java heap space明确的指出了异常发生的区域,
  • 原文地址:https://www.cnblogs.com/gjmhome/p/14400274.html
Copyright © 2020-2023  润新知