导航菜单

接雨水

🔴 困难

题目描述

给定 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.length
  • 1 <= n <= 2 * 10^4
  • 0 <= 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)

搜索