接雨水

GitHub跳转原题关系图返回列表

双指针维护左右最高柱,较矮侧水量可立即确定,O(n) 时间 O(1) 空间。

OJ: leetcodecn

题目 ID: trapping-rain-water

难度:提高+/省选-

标签:双指针动态规划数组cpppython

日期: 2026-07-28 22:05

题意

给定 n 个非负整数表示柱状图高度,计算能接多少雨水。

思路

每个位置能接的水量 = min(左边最高柱, 右边最高柱) - 自身高度。

暴力 O(n²) 每位置独立查左右最大值。优化方法有三种:

  1. 前后缀最大值:预计算 left_max 和 right_max,O(n) 空间。
  2. 单调栈:按凹槽结算,遇到更高的柱子就弹出结算。
  3. 双指针:左右指针各维护一个当前最高柱,较矮侧的水量可立即确定,并移动该侧指针。无需额外数组。

代码

cpp
/**
 * Author by Rainboy
 */
// main.cpp:双指针维护左右最高柱,较矮侧水量可立即确定,O(n) O(1)。
#include <bits/stdc++.h>
using namespace std;

class Solution {
public:
    int trap(vector<int> &h) {
        int l = 0, r = h.size() - 1, lmax = 0, rmax = 0, ans = 0;
        while (l < r) {
            if (h[l] < h[r]) {
                h[l] >= lmax ? lmax = h[l] : ans += lmax - h[l];
                l++;
            } else {
                h[r] >= rmax ? rmax = h[r] : ans += rmax - h[r];
                r--;
            }
        }
        return ans;
    }
};

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int n;
    cin >> n;
    vector<int> h(n);
    for (int &x : h)
        cin >> x;
    cout << Solution().trap(h) << '\n';
    return 0;
}
python
#!/usr/bin/env python3
from typing import List


class Solution:
    def trap(self, height: List[int]) -> int:
        l, r, lmax, rmax, ans = 0, len(height) - 1, 0, 0, 0
        while l < r:
            if height[l] < height[r]:
                if height[l] >= lmax:
                    lmax = height[l]
                else:
                    ans += lmax - height[l]
                l += 1
            else:
                if height[r] >= rmax:
                    rmax = height[r]
                else:
                    ans += rmax - height[r]
                r -= 1
        return ans


def main() -> None:
    n = int(input())
    height = list(map(int, input().split()))
    print(Solution().trap(height))


if __name__ == "__main__":
    main()

复杂度

  • 时间复杂度:O(n),双指针各遍历一次。
  • 空间复杂度:O(1),只使用几个变量。

总结

双指针解法的核心不变量是:lmax[0..l] 的最大值,rmax[r..n-1] 的最大值。height[l] < height[r] 时,lmax < rmax 不一定成立,但左侧水量由 lmax 决定已足够,因为 rmax 至少为 height[r],而 height[r] > height[l] 保证了右侧有足够高的墙。