接雨水

发布时间 2023-06-19 23:52:57作者: WhatAnyWay

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

 

没啥说的,直接把每个柱子抽象成一个木桶,只需要找到这个木桶两边的高度,根据木桶原理判断里面的水量就好了。

只需要思考一下如何确定木桶的两边就好了。

class Solution {
public:
    int trap(vector<int>& height) {
int ans=0;
if(height.size()<3) return ans;

vector<int> l;
vector<int> r;
l.push_back(height[0]);
r.push_back(height[height.size()-1]);
for(int i=1;i<height.size();i++)
{
    if(l[i-1]>height[i]) l.push_back(l[i-1]);
    else l.push_back(height[i]);
}
int j=0;
for(int i=height.size()-2;i>-1;i--)
{
if(r[j++]>height[i]) r.push_back(r[j-1]);
else r.push_back(height[i]);
}

for(int i=0;i<height.size();i++)
{
    int min=l[i]<r[height.size()-i-1]?l[i]:r[height.size()-i-1];
    ans+=min-height[i];
}

return ans;
    }
};

但是题目类型告诉我是双指针,所以应该有更好的解法。

那延展一下,直接把整体看成一个一个柱子组成的存水装置,但是这个装置里面的的存在高低不平的起伏,

怎么确定这个装置装水了?只要装置里存在小于最矮的那个柱子的起伏就行。

画个图理解下

这有一堆柱子组成的存水装置,每个柱子宽度是1,高度不一样

 首先整体抽象成整体大概就是这样

和上面对比发现,只有比左侧矮的地方才能存水

 

找第二个装置(左2和右1组成的)

对比发现,只有比右侧矮的地方才能存水

 

 再找第三个装置(左2和右5组成)

发现最后一点能存水的地方

 这样直观多了,可问题是,我双指针确定装置的两边,要找到里面小于最低边的那个柱子,额外需要一个指针去遍历,而且计算总体水量的时候也有点复杂。

那怎么优化下?

要知道,在我们找装置边界的时候,只有一个指针会移动,而且是顺序移动。

看上面的例子。一开始是个[1,8],然后找第二个[2,8],左指针移动了一步就发现一个更高的边。

之后找第三个木桶[2,5];右指针移动了三次才找到更高的边,期间它路过的 7,6俩柱子都要比它本身低,所以这里肯定会存有水。

可是循环没有结束,因为左右指针没有碰撞;

所以,右指针会继续遍历,到2这个位置才停下,期间又经历了4,3这俩比它低的柱子,那么这里也要存水。

即 3,4,6,7这个四个位置有水,看下图,确实如此。

那就直接代码实现:

class Solution {
public:
    int trap(vector<int>& height) {

int size=height.size();
int l=0;int r=size-1;
int l_l=0;int r_r=0;
int ans=0;

if(size<3) return ans;

while(l!=r)
{
l_l=height[l]>l_l?height[l]:l_l;
r_r=height[r]>r_r?height[r]:r_r;

if(height[l]<height[r])
{
    ans+=l_l-height[l];
    l++;
}
else
{
    ans+=r_r-height[r];
    r--;
}

}

return ans;
    }
};