难度:Hard
42. 接雨水
给定 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.length
1 <= n <= 2 * 10^4
0 <= height[i] <= 10^5
解法思路:
- 暴力 Time: O(n^2) Space: O(1) ans = ans + min(left_max, right_max) * height[i]
- 动态规划数组(法二)
- 栈(法三)
- 双指针(法四)
法二:
class Solution {
public int trap(int[] height) {
// 2. 动态规划数组
// Time: O(n)
// Space: O(n)
int ans = 0;
int len = height.length;
if (len < 3) return 0;
int[] leftMax = new int[len];
int[] rightMax = new int[len];
leftMax[0] = height[0];
rightMax[len - 1] = height[len - 1];
for (int i = 1; i < len; i++) {
leftMax[i] = Math.max(leftMax[i-1], height[i]);
}
for (int i = len - 2; i >= 0; i--) {
rightMax[i] = Math.max(rightMax[i+1], height[i]);
}
for (int i = 0; i < len; i++) {
ans += Math.min(leftMax[i], rightMax[i]) - height[i];
}
return ans;
}
}
法三:
class Solution {
public int trap(int[] height) {
// 3. 栈
// Time: O(n)
// Space: O(n)
Deque<Integer> stack = new ArrayDeque<>();
int ans = 0;
for (int i = 0; i < height.length; i++) {
while (!stack.isEmpty() && height[i] > height[stack.peekLast()]) {
int top = stack.pollLast();
if (stack.isEmpty()) {
break;
}
int width = i - stack.peekLast() - 1;
int diff_height = Math.min(height[i], height[stack.peekLast()]) - height[top];
ans += width * diff_height;
}
stack.addLast(i);
}
return ans;
}
}
法四:
class Solution {
public int trap(int[] height) {
// 4. 双指针
// Time: O(n)
// Space: O(1)
int left = 0, right = height.length - 1;
int leftMax = 0, rightMax = 0, ans = 0;
while (left < right) {
if (height[left] < height[right]) {
if (height[left] > leftMax) {
leftMax = height[left];
} else {
ans += leftMax - height[left];
}
left++;
} else {
if (height[right] > rightMax) {
rightMax = height[right];
} else {
ans += rightMax - height[right];
}
right--;
}
}
return ans;
}
}