题目链接
给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
上面是由数组 [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
本题对雨水的计算方法有两大类一种是竖着计算即按照列,另一种是横着计算即按照行,相对来说竖着计算好理解些。
首先我们按照列计算,求出每个元素左右的最大高度,该列能存储的水量为左右高度最大值中的较小值减去该列的高度,所以我们先分别求出每个元素左右的最大值。然后计算总和
class Solution {
public:
int trap(vector<int>& height) {
if(height.size() == 0) //这里要特判,防止为空
return 0;
int L[100010] = {0};
int R[100010] = {0};
L[0] = height[0];
for(int i = 1;i < height.size();i++)
L[i] = max(L[i - 1],height[i]);
R[height.size() - 1] = height[height.size() - 1];
for(int i = height.size() - 1;i >= 0;i--)
R[i] = max(R[i + 1],height[i]);
int ans = 0;
for(int i = 0 ;i < height.size();i++){
ans += max(0,min(R[i],L[i]) - height[i]);
}
return ans;
}
};
这里通过单调栈的思想解决,我们维持单调栈中的元素单调递减,即当前柱子的高度若低于栈顶元素或者栈为空则入栈,否则栈顶元素上方可以存放雨水,因为栈顶元素的左边是大于栈顶的(单调栈性质)而目前的元素也大于栈顶所以就形成了低洼,可以存放雨水,这里存放的雨水数可以看做一个长方形,长为(r - l - 1),高度为当前栈顶元素的高度。这里还要注意的是,若只有栈顶元素,是不能形成低洼的,所以要break出去。
class Solution {
public:
int trap(vector<int>& height) {
if(height.size() == 0)
return 0;
stack<int> st;
int ans = 0;
for(int i = 0 ; i < height.size();i++){
while(st.size() && height[st.top()] < height[i]){
int h = height[st.top()];
st.pop();
if(st.empty())
break;
int r = i;
int l = st.top();
ans += (r - l - 1) * (min(height[l],height[r]) - h);
}
st.push(i);
}
return ans;
}
};
这种方法是看LeetCode官方题解下的评论再写的,方法很巧妙而且没有使用额外空间。具体来说就是如果左边的最大值小于等于右边的最大值,那么对左边的数来说左边的最大值是可以相信的,因为左边的数都遍历过了,而右边的最大值一定大于等于当前左边的最大值,所以我们先处理左边的数。同理处理右边的数。
原文可以点这里
class Solution {
public:
int trap(vector<int>& height) {
if(height.size() == 0)
return 0;
int left = 0,right = height.size() - 1;
int left_max = 0,right_max = 0;
int ans = 0;
while(left <= right){
if(left_max <= right_max){
ans += max(0,left_max - height[left]);
left_max = max(left_max,height[left]);
left++;
}else{
ans += max(0,right_max - height[right]);
right_max = max(right_max,height[right]);
right--;
}
}
return ans;
}
};