【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
【分析】:一般情况下,如果按照人的思维方式的话,要看每一个位置可以蓄多少水,我们首先会看看,左边最高的柱子有多高(这里的左边最高还包括当前这个位置的,不是真的就是在左边的最高的柱子),右边的柱子最高的有多高,然后取他们两个当中的最小值,减去当前柱子的高度,就是这个位置可以蓄的水的量了。
class Solution {
public int trap(int[] height) {
if(height == null || height.length == 0) return 0;
int n = height.length;
int tmp, res = 0;
int maxLeft = 0, maxRight = 0;
int[] left = new int[n];
int[] right = new int[n];
for(int i=0; i<n; i++){
left[i] = maxLeft;
maxLeft = Math.max(maxLeft, height[i]);
}
for(int i=n-1; i>=0; i--){
right[i] = maxRight;
maxRight = Math.max(maxRight, height[i]);
}
for(int i=0; i<n; i++){
tmp = Math.min(left[i],right[i]);
if(tmp >= height[i]){
res += (tmp - height[i]);
}
}
return res;
}
}
[双指针法]:
而这个two pointer的算法就是,为什么非要把两边的最高的柱子都找出来再找短板呢?我们直接找短板不就好了。
为什么这样行得通呢?
因为你想啊,左边一个值记录到当前位置为止左边最高的柱子,右边一个值记录到当前位置为止右边最高的柱子,假设我们知道右边这个最高的柱子比左边那个最高的柱子矮,那么在当前位置,这个比较矮的右边最高柱一定是当前位置的短板,为什么呢?因为这个右边最高柱已经比那个左边最高柱矮了,那么即便两个
pointer 中间还有没有走完的位置,当前位置的长板也大于等于那个没有走完的左边最高柱了。所以我们就证明了,这个比较矮的板是当前位置的短板,然后用短板值减去当前柱子的高度就是当前位置蓄水量了。
整个vector扫一遍就是o(n)时间复杂度,左边一个pointer,右边一个pointer,还有两个值分别记录左边最高柱、右边最高柱,还有一个值记录蓄水量。所以是o(1)空间复杂度。
时间复杂度分析:o(n)
class Solution {
public int trap(int[] height) {
if(height == null || height.length == 0) return 0;
int n = height.length;
int l = 0, r = n-1;
int res = 0;
int maxL = 0, maxR = 0;
while(l < r){
maxL = Math.max(maxL, height[l]);
maxR = Math.max(maxR, height[r]);
if(maxL < maxR){
res += maxL - height[l++];
}else{
res += maxR - height[r--];
}
}
return res;
}
}