给定 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
思路
可以假设有柱子的地方都可以盛满水,即柱子高度+雨水高度= 最高柱子的高度,这样可以盛的总雨水为:柱子的占地(size)× 最高柱子的长度;
这样子的话我们就只要计算两端可能会漏掉的雨水就可以了;
首先先找到最左端和最右端的最高柱子的位置;
然后从两端计算漏掉的雨水;
在最高柱子之间的雨水不会漏掉所以可以不用计算;
最后根据:盛的总雨水= size*maxValue- 会漏掉的雨水- 柱子的面积 计算出结果
class Solution {
public:
int trap(vector<int>& height) {
// 删掉两边的0
int size= height.size();
int l= 0;
while(l< size&&!height[l]) l++;
int r= size- 1;
while(r>= 0&&!height[r]) r--;
// 去除0后数组的长度小于2时,返回0
if(r- l< 2) return 0;
height= vector<int>(height.begin()+ l, height.end()- (size- r)+ 1);
size= height.size();
// 找到最大值的最左和最右的位置
int maxValue= 0x80000000;
int maxLeft= 0, maxRight= 0;
int sum= 0;
for(int i= 0; i< size; i++){
if(height[i]> maxValue){
maxValue= height[i];
maxLeft= maxRight;
maxRight= i;
}
sum+= height[i];
}
if(height[maxLeft]!= height[maxRight]) maxLeft= maxRight;
// 从左边开始计算会漏掉的雨水
int maxTemp= 0;
int i= -1;
int subSum= 0;
while(++i< maxLeft){
maxTemp= maxTemp> height[i]? maxTemp: height[i];
subSum+= (maxValue- maxTemp);
}
// 从右边开始计算会漏掉的雨水
maxTemp= 0;
i= size;
while(--i> maxRight){
maxTemp= maxTemp> height[i]? maxTemp: height[i];
subSum+= (maxValue- maxTemp);
}
// 最后的雨水= size*maxValue- 会漏掉的雨水- 柱子的面积
return size* maxValue- subSum- sum;
}
};
参考Leetcode题解中的官方题解中的双指针法,码了一遍
双指针法在计算其中一端的时候确保了另一端有比当前柱子高的
class Solution {
public:
int trap(vector<int>& height) {
int maxLeft= 0, maxRight= 0;
int left= 0, right= height.size()- 1;
int result= 0;
while(left<= right){
if(height[left]< height[right]){
height[left]> maxLeft? (maxLeft= height[left]): (result+= (maxLeft- height[left]));
++left;
}
else{
height[right]> maxRight? (maxRight= height[right]): (result+= (maxRight- height[right]));
--right;
}
}
return result;
}
};