(6)LeetCode.42 接雨水

LeetCode.42 接雨水

题目描述

给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。

示例:

复制代码
输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]
输出:6

方法一:前缀最大值 + 后缀最大值(动态规划)

思路分析

对于每一个位置 i,它能接的雨水量取决于它左边最高的柱子和右边最高的柱子中较矮的那一个(木桶效应)。即:

复制代码
water[i] = min(左边最高, 右边最高) - height[i]

如果这个差值为负,则取 0。

我们可以预先计算两个数组:

  • pre_max[i]:表示从下标 0 到 i 的最大高度(前缀最大值)。
  • suf_max[i]:表示从下标 i 到 n-1 的最大高度(后缀最大值)。

然后遍历每个位置累加 min(pre_max[i], suf_max[i]) - height[i] 即可。

代码实现

cpp 复制代码
class Solution {
public:
    int trap(vector<int>& height) {
        int n = height.size();
        vector<int> pre_max(n);
        pre_max[0] = height[0];
        for (int i = 1; i < n; ++i)
            pre_max[i] = max(pre_max[i - 1], height[i]);

        vector<int> suf_max(n);
        suf_max[n - 1] = height[n - 1];
        for (int i = n - 2; i >= 0; --i)
            suf_max[i] = max(suf_max[i + 1], height[i]);

        int ans = 0;
        for (int i = 0; i < n; ++i)
            ans += min(pre_max[i], suf_max[i]) - height[i];
        return ans;
    }
};

复杂度分析

  • 时间复杂度:O(n),遍历三次数组。
  • 空间复杂度:O(n),使用了两个辅助数组。

方法二:双指针

思路分析

方法一需要额外 O(n) 的空间,实际上我们可以用两个指针和两个变量在遍历过程中动态维护左右两侧的最大高度,将空间优化到 O(1)。

核心思想:

leftright 指针分别指向数组的两端,并维护 pre_maxsuf_max 分别表示 [0, left] 的最大值和 [right, n-1] 的最大值。

在每一轮中,比较 pre_maxsuf_max

  • 如果 pre_max < suf_max,则对于 left 位置,它的右侧最大高度至少为 suf_max,因此该位置的积水高度由 pre_max 决定,累加 pre_max - height[left] 并右移 left
  • 否则,对称处理 right 位置。

为什么这样正确?因为当 pre_max < suf_max 时,left 位置的右侧最大高度一定 ≥ suf_max > pre_max,所以 min(左侧最大, 右侧最大) = pre_max,该位置接水量确定。移动指针后,新的 pre_maxsuf_max 会更新,继续处理下一个位置。

代码实现

cpp 复制代码
class Solution {
public:
    int trap(vector<int>& height) {
        int ans = 0, pre_max = 0, suf_max = 0;
        int left = 0, right = height.size() - 1;
        while (left < right) {
            pre_max = max(pre_max, height[left]);
            suf_max = max(suf_max, height[right]);
            if (pre_max < suf_max) {
                ans += pre_max - height[left];
                ++left;
            } else {
                ans += suf_max - height[right];
                --right;
            }
        }
        return ans;
    }
};

复杂度分析

  • 时间复杂度:O(n),每个元素被访问一次。
  • 空间复杂度:O(1),只使用了常数个变量。

方法三:单调栈

思路分析

单调栈解法通过维护一个递减栈来寻找凹槽,并按层计算积水量。

栈中存储的是柱子的下标,保证从栈底到栈顶对应的高度是递减的。遍历每个柱子:

  • 如果当前柱子高度小于等于栈顶高度,则入栈(维持递减)。
  • 如果当前柱子高度大于栈顶高度,说明栈顶柱子可以作为凹槽的底部。弹出栈顶作为 bottom,此时新的栈顶就是凹槽的左边界 left,当前柱子 i 是右边界。那么这一层的积水高度为 min(height[left], height[i]) - height[bottom],宽度为 i - left - 1,累加结果。重复这个过程直到栈空或栈顶高度不小于当前高度。

注意:当高度相等时,我们同样会弹出旧的栈顶,并用新的下标代替,这样可以避免重复计算,且不影响最终结果。

代码实现

cpp 复制代码
class Solution {
public:
    int trap(vector<int>& height) {
        int ans = 0;
        stack<int> st; // 存储下标,保证栈中高度递减
        for (int i = 0; i < height.size(); ++i) {
            int h = height[i];
            while (!st.empty() && height[st.top()] <= h) {
                int bottom_h = height[st.top()];
                st.pop();
                if (st.empty()) break; // 左边没有更高的柱子,无法形成凹槽
                int left = st.top();
                int dh = min(height[left], h) - bottom_h; // 这一层的高度
                int width = i - left - 1;
                ans += dh * width;
            }
            st.push(i);
        }
        return ans;
    }
};

复杂度分析

  • 时间复杂度:O(n),每个元素入栈一次,出栈一次。
  • 空间复杂度:O(n),栈在最坏情况下需要存储所有下标(如高度递减的情况)。

三种方法对比

方法 时间复杂度 空间复杂度 核心思想
前缀后缀 O(n) O(n) 预先计算每个位置左右的最大值,直接累加
双指针 O(n) O(1) 动态维护左右最大高度,每次处理较矮一侧
单调栈 O(n) O(n) 用递减栈寻找凹槽,按层计算水量
  • 前缀后缀最容易理解,但空间开销较大。
  • 双指针是空间最优解,代码简洁,面试中常被要求写出。
  • 单调栈思路巧妙,适合作为扩展解法,体现对问题结构的深入理解。

总结

接雨水问题是一道经典的面试题,三种解法分别代表了动态规划、双指针、单调栈三种不同的思想。掌握它们不仅能解决本题,还能帮助你处理其他类似问题(如柱状图中最大的矩形、每日温度等)。

相关推荐
啦啦啦啦啦zzzz8 分钟前
Logger的组装(c++20)
c++·算法·c++20
尾善爱看海1 小时前
前端算法与手写题集
前端·算法
程序员阿鹏2 小时前
为什么MySQL InnoDB选择B+树?
数据结构·数据库·b树·sql·mysql·算法·缓存
AI 思录2 小时前
Prompt 事故档案(八):日常表达被标为“待校准”,AI 的爹味语法从哪里来
大数据·人工智能·算法·prompt·用户体验·ai合规
月光船幽幽2 小时前
跨范式映射的稳定接口设计
人工智能·python·算法
郝学胜-神的一滴3 小时前
C++11 工程级应用 09:告别无谓拷贝,解锁高性能移动语义
开发语言·数据结构·c++·vscode·软件工程·visual studio
2601_965742223 小时前
全媒体运营与短视频代运营,两者有什么区别?
大数据·数据结构·人工智能·算法·ai·媒体
wordbaby5 小时前
混合检索:两全其美的艺术
人工智能·算法
彧azz5 小时前
数据结构:关于图的学习
c语言·数据结构·笔记·学习·算法
热心网友俣先生5 小时前
A题-药材的烘干问题-题意逐句翻译
算法·数学建模