LeetCode 热题 100 之第7题 接雨水(JavaScript篇)

133 阅读3分钟

传送门:42. 接雨水 - 力扣(LeetCode)


🧠 题目描述

给定 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 * 104
  • 0 <= height[i] <= 105

✅ 解法:双指针 + 左右最大值判断

通过这种方法可以避免了暴力法或动态规划中额外空间的开销。


🔍 变量说明

let res = 0;        // 最终能接住的雨水总量
let l = 0;          // 左指针
let r = height.length - 1;  // 右指针
let pMax = 0;       // 左边最高的柱子高度(从左往右扫描)
let sMax = 0;       // 右边最高的柱子高度(从右往左扫描)

🔄 核心逻辑解析

while (l < r) {
    pMax = Math.max(pMax, height[l]);
    sMax = Math.max(sMax, height[r]);

    if (pMax < sMax) {
        res += pMax - height[l++];
    } else {
        res += sMax - height[r--];
    }
}

1. 更新左右两边的最大高度

  • pMax = Math.max(pMax, height[l]):记录左边当前最大高度。
  • sMax = Math.max(sMax, height[r]):记录右边当前最大高度。

2. 比较决定哪边可以积水

  • 因为水的高度由较低的一侧决定(木桶原理),所以:
    • 如果 pMax < sMax,那么当前位置 l 能接到的水量就是 pMax - height[l]
    • 同理,如果 sMax <= pMax,那么当前位置 r 能接到的水量是 sMax - height[r]

3. 移动指针

  • 如果处理了 l,就 l++
  • 如果处理了 r,就 r--

📊 示例演示(一步步走)

以输入 [0,1,0,2,1,0,1,3,2,1,2,1] 为例:

lrpMaxsMax操作res
01101pMax < sMax → 左:0-0=00
11111相等 → 右:1-1=00
11012pMax < sMax → 左:1-1=00
21012pMax < sMax → 左:1-0=11
31022相等 → 右:2-2=01
3922相等 → 右:2-1=12
3822相等 → 右:2-2=02
3723pMax < sMax → 左:2-2=02
4723pMax < sMax → 左:2-1=13
5723pMax < sMax → 左:2-0=25
6723pMax < sMax → 左:2-1=16

→ 循环结束(l=7, r=7),返回 6

最终结果:res = 6


⏱️ 时间 & 空间复杂度

  • 时间复杂度:O(n)
    每个元素最多被访问一次,l 和 r 向中间靠拢。

  • 空间复杂度:O(1)
    只用了几个变量,没有使用额外数组或栈。


解题代码

/**
 * @param {number[]} height
 * @return {number}
 */
var trap = function(height) {
    let res = 0, l = 0, r = height.length - 1, pMax = 0, sMax = 0;
    while (l < r) {
        pMax = Math.max(pMax, height[l]);
        sMax = Math.max(sMax, height[r]);
        if (pMax < sMax) {
            res += pMax - height[l++];
        } else {
            res += sMax - height[r--];
        }
    }
    return res;
};

✅ 总结一句话:

这段代码通过两个指针从两端向中间遍历,利用“当前左右两侧最高柱子”的最小值减去当前柱子高度,来计算每一格能接住的水量,是一种非常高效的贪心算法。