LeetCode 42:接雨水 双指针+模拟

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

在这里插入图片描述

上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。 感谢 Marcos 贡献此图。

示例:
输入: [0,1,0,2,1,0,1,3,2,1,2,1]
输出: 6

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/trapping-rain-water
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

先从简单的问题 入手,假设柱子是:

[1, 0, 2]

我们很容易想到

  • 选取一根柱子l,使得右边边柱子l+1低于l
  • l+2开始选取第一根大于等于l高度的柱子r
  • 计算中间的水量,加入答案
  • 如果找不到柱子高于l,那么选取l+1作为l,重新开始

对于“左边小于右边”这种情况,我们很容易填满
在这里插入图片描述
可是如果出现这种情况:
在这里插入图片描述
我们只能填满蓝色区域,红色区域被忽略了

那么我们先填满蓝色区域,再从右到左模拟一次就好了

在这里插入图片描述
基本思路:

  1. 从左到右枚举左端点,找第一个大于等于左端点的右端点,计算水量,左端点移到右端点,重复
  2. 填满1中计算过的地方,填充到上限: l, r 两个端点的最小值
  3. 从右到左枚举右端点,找第一个大于等于右端点的左端点,计算水量,右端点移到左端点,重复

代码

class Solution {
public:
    int trap(vector<int>& height)
    {
        if(height.size()<3) return 0;
        int l=0, r=0, ans=0;
        // 从左到右
        while(l+2<height.size())
        {
            // 找合法左端点
            while(l+2<height.size() && height[l+1]>=height[l]) l++;
            r=l+2;
            // 找第一个大于等于左端点的右端点
            while(r<height.size() && height[r]<height[l]) r++; 
            if(r==height.size()){l++; continue;}
            // 计算,填坑
            for(int i=l+1; i<=r-1; i++)
            {
                ans += min(height[l], height[r])-height[i];
                height[i] = min(height[l], height[r]);
            }
            l=r;
        }
        // 从右到左
        r = height.size()-1;
        while(r-2>=0)
        {
            while(r-2>=0 && height[r-1]>=height[r]) r--;
            l=r-2;
            while(l>=0 && height[l]<height[r]) l--;
            if(l==-1){r--; continue;}
            for(int i=l+1; i<=r-1; i++)
                ans += min(height[l], height[r])-height[i];
            r=l;
        }
        return ans;
    }
};
发布了238 篇原创文章 · 获赞 7 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_44176696/article/details/104863714