题目
给定 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.length1 <= n <= 2 * 10^4-
解题方法
动态规划
每一列能够接的雨水量有该列左右两侧的最大值的较小值决定,因此可以预处理处每一列对应的左侧和右侧最大值,进而计算该列能够承接的雨水量。
时间复杂度O(n),空间复杂度O(n)。
C++代码:class Solution {public:int trap(vector<int>& height) {int size = height.size();vector<int> rest(size, INT_MAX);int lmax = height[0], rmax = height[size-1];for(int i=0; i<size; i++) {lmax = lmax > height[i] ? lmax : height[i];rmax = rmax > height[size-1-i] ? rmax : height[size-1-i];rest[i] = rest[i] < lmax ? rest[i] : lmax;rest[size-1-i] = rest[size-1-i] < rmax ? rest[size-1-i] : rmax;}int result = 0;for(int i=0; i<size; i++) {result += (rest[i]-height[i]);}return result;}};
单调栈
使用递增单调栈保存递减序列,当寻找到下一个更大元素时,弹出当前元素,并根据前一个元素对当前元素所在位置进行雨水填充。

时间复杂度O(n),空间复杂度O(n)。
C++代码:class Solution { public: int trap(vector<int>& height) { int size = height.size(); stack<int> st; int result = 0; for(int i=0; i<size; i++) { while(!st.empty() && height[i]>height[st.top()]) { int mid = height[st.top()]; st.pop(); if(!st.empty()) { result += (min(height[i], height[st.top()])-mid) * (i-st.top()-1); } } st.push(i); } return result; } };双指针
左右指针分别从左端和右端向中间移动,过程中维护左侧最大值与右侧最大值,通过
height[left]和height[right]决定填充以及指针移动:- 如果
height[left]<height[right],则对于left处的元素必有lmax<lmax,故通过lmax填充left处,并将left右移。 - 如果
height[left]≥height[right],则对于right处的元素必有lmax≥rmax,通过rmax填充right处,并将right左移
时间复杂度O(n),空间复杂度O(1)。
C++代码:
class Solution {
public:
int trap(vector<int>& height) {
int result = 0;
int left = 0;
int right = height.size()-1;
int lmax = 0;
int rmax = 0;
while(left<right) {
lmax = max(height[left], lmax);
rmax = max(height[right], rmax);
if(height[left]<height[right]) {
result += lmax-height[left];
left++;
}
else {
result += rmax-height[right];
right--;
}
}
return result;
}
};
