给定
n个非负整数表示每个宽度为1的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
样例
Example
示例 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 * 10^40 <= height[i] <= 10^5
思路
- 前缀数组:对于每个柱子,上方水的高度取决于它左边最高的柱子和右边最高的柱子的较小侧,因此我们可以通过前缀数组计算出每一个柱子左右的最高柱子,然后用
ans += min(leftMax[i], rightMax[i]) - height[i]累加计算结果。为了避免左右最大高度小于自身,所以自己也参加左右最大高度计算。 - 双指针一:使用双指针维护左右从外向里维护左右最大高度,对于较小的一侧所处柱子进行计算,因为该柱子的较小方最大高度是已知的,另一方最大高度虽未知,但一定大于目前的最大高度,因而也大于较小一侧最大高度。
答案
Java
// 前缀数组
class Solution {
public int trap(int[] height) {
int n = height.length, ans = 0;
int[] lh = new int[n], rh = new int[n];
lh[0] = height[0];
rh[n - 1] = height[n - 1];
for (int i = 1; i < n; i++) {
lh[i] = Math.max(lh[i - 1], height[i]);
}
for (int i = n - 2; i >= 0; i--) {
rh[i] = Math.max(rh[i + 1], height[i]);
}
for (int i = 0; i < n; i++) {
ans += Math.min(lh[i], rh[i]) - height[i];
}
return ans;
}
}
// 双指针一
class Solution {
public int trap(int[] height) {
int n = height.length, l = 0, r = n - 1, ans = 0, lh = height[l], rh = height[r];
while (l < r) {
if (lh > rh) {
ans += rh - height[r];
r--;
rh = Math.max(rh, height[r]);
} else {
ans += lh - height[l];
l++;
lh = Math.max(lh, height[l]);
}
}
return ans;
}
}