给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
示例 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.length1 <= n <= 2 * 1040 <= height[i] <= 105
#思路
如果知道柱子i的左右两侧最大柱子的高低差,我们就可以得出i的积水
暴力法:循环遍历i,求出左右两侧最值就可以求出解,但明显O(n^2)
如何优化左右两侧的最值呢?
如果有一个左指针,那随着右移必然可以同时更新左边的最值,此时如果右侧任意位置发现超过左边max的高度,那么就以maxleftH-height得到雨水数量;
同理如果有一个右指针,那随着左移必然可以同时更新右边的最值,如果左边任意位置发现超过右边最大高度的高柱子,那么就以maxRightH-height得到雨水数量;
最终我们结合在一起,同时用两个指针相向而行,根据两个指针遍历时候更新的左右最值,按条件至少能得到左右指针其中一个的积水数,从而做到O(N)
public int trap(int[] height) {
if (height.length < 3)
return 0;
int left = 1;
int right = height.length - 2;
int maxLeft = height[0];
int maxRight = height[height.length - 1];
int res = 0;
while (left <= right) {
//去求右指针积水
if (maxLeft > maxRight) {
res += maxRight > height[right] ? maxRight - height[right] : 0;
maxRight = Math.max(maxRight, height[right]);
right--;
} else if (maxLeft <= maxRight) {
res += maxLeft > height[left] ? maxLeft - height[left] : 0;
maxLeft = Math.max(maxLeft, height[left]);
left++;
}
}
return res;
}