LeetCode-双指针-接雨水
✏️ 关于专栏:专栏用于记录
prepare for the coding test
。
📝 接雨水
🎯题目描述
给定
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
🧪前后缀分解

-
用一个数组记录从左到右当前以及当前左边范围内的最大高度
-
用一个数组记录从右到左当前以及当前右边范围内的最大高度
-
遍历数组用当前位置左边/右边中较小的减去当前高度
class Solution {
public:
int trap(vector<int>& height) {
vector<int>preRecord(height.size());
vector<int>sufRecord(height.size());
int curMax = 0;
for(int i = 0;i < height.size();i++){
curMax = max(height[i],curMax);
preRecord[i] = curMax;
}
curMax = 0;
for(int i = height.size() - 1;i >= 0;i--){
curMax = max(height[i],curMax);
sufRecord[i] = curMax;
}
int ans = 0;
for(int i = 0;i < height.size();i++){
ans += min(preRecord[i],sufRecord[i]) - height[i];
}
return ans;
}
};
🧪相向双指针
-
用两个指针
left
和right
从数组两端出发; -
分别用
left_max
和right_max
记录左右走过的最大高度; -
每次比较:
-
如果
left_max < right_max
,说明左边是矮墙,决定积水高度:water += left_max - height[left]
然后左指针右移;
-
否则右边矮,右指针左移,进行相同处理。
-
因为当前能装多少水,是由矮的一边决定的,哪边小就先动哪边。

class Solution {
public:
int trap(vector<int>& height) {
int ans = 0,left = 0,right = height.size() - 1,pre_max = 0,suf_max = 0;
while(left <= right){
pre_max = max(pre_max,height[left]);
suf_max = max(suf_max,height[right]);
ans += pre_max < suf_max ? pre_max - height[left++] : suf_max - height[right--];
}
return ans;
}
};
🧪单调栈
单调栈是一种特殊的栈结构,用于维护元素单调递增或单调递减的性质。
在本题中,我们使用单调递减栈:栈顶到栈底的元素(对应柱子的高度)是从高到低排列的。
我们要找的是所有“凹槽”区域,即:一个较高柱子 → 一个较低柱子 → 再一个较高柱子,中间就能形成积水结构。
找出所有的凹槽结构,这些地方会积水。
栈的作用是:帮助我们找到“当前柱子右边第一个比它高的柱子”以及“左边那个比它高的柱子”。
准备一个栈,存放的是柱子的下标;
从左到右遍历每个柱子:
- 如果当前柱子的高度小于栈顶柱子高度,说明还没形成凹槽,入栈;
- 如果当前柱子高于栈顶柱子,说明凹槽右墙出现了,此时可以接水:
- 弹出中间的柱子,记为
bottom
; - 栈顶现在是左墙,当前是右墙;
- 计算宽度 = 当前索引 - 左墙索引 - 1
- 计算高度 = min(左墙高度, 右墙高度) - bottom 高度
- 乘起来就是这一段能接的水。
- 弹出中间的柱子,记为
重复这个过程,直到遍历结束。

class Solution {
public:
int trap(vector<int>& height) {
int ans = 0;
stack<int> st;
for (int i = 0; i < height.size(); i++) { ························
while (!st.empty() && height[i] >= height[st.top()]) {
int bottom_h = height[st.top()];
st.pop();
if (st.empty()) {
break;
}
int left = st.top();
int dh = min(height[left], height[i]) - bottom_h; // 面积的高
ans += dh * (i - left - 1);
}
st.push(i);
}
return ans;
}
};
🌟 总结
方法 | 原理通俗理解 | 是否推荐 | 特点与场景说明 |
---|---|---|---|
前后缀最大 | 每个柱子左右最高决定水面高度 | ✅ 简单直观 | 新手首选,代码可读性好 |
双指针 | 左右两端往中间走,谁低谁先结算 | ✅ 推荐 | 空间复杂度最优,面试常用 |
单调栈 | 模拟凹槽结构,左墙 - 凹槽 - 右墙三者一组 | ✅ 进阶 | 结构巧妙,适合算法进阶题目 |
🎯 刷题训练推荐(单调栈)
刷题顺序建议:
496. 下一个更大元素 I
✅503. 下一个更大元素 II
✅(循环数组)739. 每日温度
✅84. 柱状图中最大矩形
🔥42. 接雨水(本题)
🔥🔥85. 最大矩形(二维拓展)
🔥🔥🔥