自学内容网 自学内容网

接雨水(双指针做法 详细思路)

题目来源

42. 接雨水 - 力扣(LeetCode)


题目描述

给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。

示例 1:

输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]
输出:6
解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。 

示例 2:

输入:height = [4,2,0,3,2,5]
输出:9

提示:

  • n == height.length
  • 1 <= n <= 2 * 104
  • 0 <= height[i] <= 105

题目限制

要求做法是双指针,最优解


思路分析(双指针思路怎么来的?)

这道题目呢,其实说实话,我第一次做是看答案的,自己做感觉很难能够想的出来,而我又看了好多的讲解,得出一个结论:

大家看答案不一定能够真的懂,就大部分题解,都讲解的是纯代码的内容,他没有讲到本质的逻辑,这样的话会造成大家对这道题影响不深刻,没有真正本质上理解,所以说我就给大家讲讲这个底层的逻辑

我们从最左边开始模拟

左边第一个位置,当前位置高度是0,上界也是0,那么能接的雨水量就是上界减去当前高度,得到0. 

左边第二个位置,当前位置高度是1,上界从上次的0,更新为当前的1,即当前高度就是上界,因此,能接的雨水量就是上界减去当前高度,得到0。

左边第三个位置,当前位置高度是0,上界保留上次的1,则,能接的雨水量就是上界减去当前高度,得到1.

左边第四个位置,同第二个位置,上界更新为2,能接的雨水量为0

左边第五个位置,能接的雨水量:上界2-当前高度1=1

左边第六个位置,能接的雨水量:上界2-当前高度0=2

左边第七个位置,能接的雨水量:上界2-当前高度1=1

左边第八个位置,上界更新为3,能接的雨水量:上界3-当前高度3=0

左边第九个位置,能接的雨水量:上界3-当前高度2=1

但是!由图可知,这个位置如果要能接水1,那么右侧就应该有比当前位置更高的一个边界,可以把水接住,否则就会从右侧漏掉

因此,单纯的从左往右是不行的——所以我们用双指针


 

在我红框框起来的这一部分,我们可以知道:实际上, 1、2、3这三个位置,他们的接水量是由左右两边决定的,而且,决定“上界”(上界就是2,再降雨的话就会从左边边界漏出)的是左右两边较小的边界。

所以说,我们就以这个局部图为例子:

编号1 2 3 4 5

既然我们要用双指针,那么我们就先定义一下:left=1   right=5

此时,左右上界分别为2 3

 因为上面我们已经分析过,小的那个上界才决定能接多少水,所以我们从左边开始

(假设从右边开始的话,加入3位置高度是2呢,那你4的位置接水量=右边上界3-当前位置1=2,但是实际为1,就是因为这样的话,左边就会漏掉,所以说接水会接不住,所以我们从较小的上界开始

之后的内容就和上面模拟的是一样的


具体代码

class Solution {
public:
    int trap(vector<int>& height) {
       int ys=0;
       int l=0,r=height.size()-1;
       int lup=0,rup=0;
       while(l<r)
       {
        lup=max(lup,height[l]);
        rup=max(rup,height[r]);
        if(height[l]<height[r])ys+=lup-height[l++];
        else ys+=rup-height[r--];
       }return ys;
    }
};

代码解释 

首先,定义了几个变量

ys表示接收雨水量,初始化为0

l就是left,代表左边的当前位置

r就是right,代表右边的当前位置

lup就是leftup,代表左边的上界

rup就是rightup,代表右边的上界

然后,第一步,比较,得出左右上界的值是多少?也就是max值和当前高度比较,取大的那个:

lup=max(lup,height[l]);
rup=max(rup,height[r]);

 

第二步,判断谁起决定性作用,左边当前位置和右边当前位置比较,取小的那个方向,进行操作,左边的话就是左上界减去当前左边高度,右边的话同理,右上界减去当前右边高度:

 if(height[l]<height[r])ys+=lup-height[l++];
 else ys+=rup-height[r--];

第三步,while循环结束,左边操作位置和右边操作位置重合:

所以循环语句是while(l<r)

最后,返回一下接收水量ys即可:

return ys;


注意事项

我们在做这道题的时候,脑子里一定要有思路,而不是对于代码解释的简单吸收和模拟,要知道这样做的底层逻辑是什么,知道了原理,就不容易忘,下次还能做出来,一定要培养自己对于这道题的思路


总结要点

最后我再来总结一下这道题解题要点:

1.知道“上界”是什么?

2.每个位置的接收雨水量的计算公式要知道:接收雨水量=当前的上界-当前高度

3.除了知道当前位置的接收雨水量计算公式,目光还不能局限于就这当前一个位置,而要看左右,如果说发生了漏水情况怎么办?

4.因此,要对于左右的最大值进行比较,从较小的上界处开始操作,如果选了大的那个,那么在后续位置操作时就有可能漏水,从较小的上界那一侧漏出去了

知道了这四点,我们就能够把整个代码理顺,搞清楚底层逻辑,不容易忘记

另外,这是腾讯的面试题,据说连腾讯公司里面的保洁阿姨和保安大哥都会做呢!不会做的要加油啦!😄


原文地址:https://blog.csdn.net/ajsjnnn/article/details/144328348

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!