接雨水
🔴 困难题目描述
给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
示例 1
输入:height = [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
解法一
参考答案 (2 个标签)
双指针 O(n)
思路
左右两个指针向中间移动,每次处理较矮的一侧。当前柱子能接的雨水 = min(左侧最高, 右侧最高) - 当前高度。
代码实现
/**
* @param {number[]} height
* @return {number}
*/
function trap(height) {
let left = 0, right = height.length - 1;
let leftMax = 0, rightMax = 0;
let water = 0;
while (left < right) {
if (height[left] < height[right]) {
if (height[left] >= leftMax) {
leftMax = height[left];
} else {
water += leftMax - height[left];
}
left++;
} else {
if (height[right] >= rightMax) {
rightMax = height[right];
} else {
water += rightMax - height[right];
}
right--;
}
}
return water;
}复杂度分析
- 时间复杂度:O(n)
- 空间复杂度:O(1)
解法二
参考答案 (2 个标签)
单调栈 O(n)
思路
维护单调递减栈,当遇到比栈顶高的柱子时,计算能接的雨水。
代码实现
/**
* @param {number[]} height
* @return {number}
*/
function trap(height) {
const stack = [];
let water = 0;
for (let i = 0; i < height.length; i++) {
while (stack.length > 0 && height[i] > height[stack[stack.length - 1]]) {
const mid = stack.pop();
if (stack.length === 0) break;
const left = stack[stack.length - 1];
const h = Math.min(height[left], height[i]) - height[mid];
const w = i - left - 1;
water += h * w;
}
stack.push(i);
}
return water;
}复杂度分析
- 时间复杂度:O(n)
- 空间复杂度:O(n)
