给定 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; } };