给定 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
思路,双指针法,找最大值max,表明最大值左边水面只可能由左到右慢慢升高,最大值右边水面只可能从右到左慢慢下降。
从最大值点把数组分成两部分,[begin,maxposition]闭区间,[maxposition,end]这个问题简化成一个问题,已知左/右边最高,求能接多少雨水?不失一般性,另右边最高,解左区间问题。单指针:
试想,这时,任何一点 i 的水面高度一定一定一定是从【0,i】之间的最大值,和峰值max之间的最小值(这句话好好理解!!),这样问题就很简单了,从0开始遍历,一直更新我的leftmaxnum,如果需要更新,则这个点一定不存水,如果不更新,一定存leftmaxnum-height[i]高度的水,求和即可。
右区间同左。
代码如下:
class Solution {
public:
int trap(vector<int>& height) {
if(height.size()==0) return 0;
int maxn=0;
auto maxloc=height.begin();
for(auto a=height.begin();a!=height.end();a++){
if(*a>maxn){
maxn=*a;maxloc=a;
}
}
auto leftpt = height.begin();
int leftmaxnum=height[0];
int sum=0;
while(leftpt!=maxloc){
if(*leftpt<leftmaxnum) sum+=(leftmaxnum-*leftpt);
else{leftmaxnum=*leftpt;}
leftpt++;
}
int rightmaxnum=0;
auto rightpt = height.end()-1;
while(rightpt!=maxloc){
if(*rightpt<rightmaxnum) sum+=(rightmaxnum-*rightpt);
else{rightmaxnum=*rightpt;}
rightpt--;
}
return sum;
}
};