给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]
输出:6
解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。
示例 2:
输入:height = [4,2,0,3,2,5]
输出:9
n == height.length
0 <= n <= 3 * 104
0 <= height[i] <= 105
1.其实每个位置位置都可以看自己是不是有雨水囤积
2.例如图示,其实囤积雨水的量是water[2]+water[4]+water[5]+water[6]+water[9]
3.而每个位置的雨水,其实只和当前位置的左边的最大值和右边的最大值相关
4.例如water[5]其实只和height[3]相关,不受到临近两个柱子的影响
5.water[5] = height[3]-height[5] 也就是当前位置柱子的积水等于当前位置左边的最小值和右边的最小值中的小的一个柱子的高度减去当前位置的高度
6.那么可以建立一个双指针,左右同时进行遍历,将每个位置的积水量加起来
7.如果左边最大值比较小,那么移动左指针,如果右边最大值比较小,那么移动右指针
class Solution {
public int trap(int[] height) {
//其实每个位置位置都可以看自己是不是有雨水囤积
//例如图示,其实囤积雨水的量是water[2]+water[4]+water[5]+water[6]+water[9]
//而每个位置的雨水,其实只和当前位置的左边的最大值和右边的最大值相关
//例如water[5]其实只和height[3]相关,不受到临近两个柱子的影响
//water[5] = height[3]-height[5] 也就是当前位置柱子的积水等于当前位置左边的最小值和右边的最小值中的小的一个柱子的高度减去当前位置的高度
//那么其实问题就变成将每个位置的雨水加起来
if(height==null||height.length<=2) return 0;
int len = height.length;
//首先边界定义为左边最大值和右边最小值
int lMax = height[0];
int rMax = height[len-1];
//积水要从除了最左边和最右边的柱子开始积水
int left = 1;
int right = len-1;
int water = 0;
while(left<=right) {
//找到左边的最大高度和右边的最大高度
lMax = Math.max(lMax,height[left]);
rMax = Math.max(rMax,height[right]);
//如果左边的比较低,那么当前的水位就是左边的最大高度减去当前位置的柱子高度
if(lMax<rMax) {
water+=lMax-height[left];
left++;
}else {
//右边的就是右边的最大高度减去当前位置的高度
water+=rMax-height[right];
right--;
}
}
return water;
}
}