1 题目
Given n non-negative integers representing an elevation map where the width of each bar is 1, compute how much water it is able to trap after raining.
The above elevation map is represented by array [0,1,0,2,1,0,1,3,2,1,2,1]. In this case, 6 units of rain water (blue section) are being trapped. Thanks Marcos for contributing this image!
Example:
Input: [0,1,0,2,1,0,1,3,2,1,2,1]
Output: 6
2 尝试解
2.1 分析
给定一个非负整数的数组,代表板块i的高度,每个板块宽度都是1。问下雨后,能存储的水的体积。
找到最高的板块,将数组分为左右两部分。每个存水的区域都由左右两个板块组成,中间的板块均比两端低。所以从左边第一个非零板块起,向右遍历板块height[i],如果遇到更低的板块,temp += height[i]表示该存水区被板块占掉的部分。直到遇到更高或者相等的板块,则构成一个存水区,result += (height[R] - height[L])*(L-R-1) - temp。直到达到最高板块。同理从右向左也寻找存水区。
但是上述方法有一个问题,如果最高板块有重复,则任意两个最高板块之间的区域将被重复计算。
考虑修改遍历过程,从左边第一个非零板块起,向右遍历板块height[i],直到遇到更高的板块才认为形成一个存水区。但是这种修改在最高板块有重复时,任意两个最高板块之间的区域将被忽略。
结合两种情况来看,可以将从左向右遍历时,遇到更高或者相等的板块则计算一次,从右向左遍历时,遇到更高的板块才计算一次。这样任意两个最高板块之间的区域将在从左向右遍历时被记录,而从右向左遍历时被忽略。
2.2 代码
class Solution {
public:
int trap(vector<int>& height) {
pair<int,int> left{-1,-1};
pair<int,int> right{-1,-1};
int result = 0;
int temp = 0;
for(int i = 0; i < height.size(); i++){
if(left.first == -1 || height[i] > left.first){
if(left.first != -1){
result += left.first*(i-left.second-1)-temp;
}
left.first = height[i];
left.second = i;
temp = 0;
}
else{
temp += height[i];
}
}
temp = 0;
for(int i = height.size()-1; i >= 0; i--){
if(right.first == -1 || height[i] >= right.first){
if(right.first != -1){
result += right.first*(right.second-i-1)-temp;
}
right.first = height[i];
right.second = i;
temp = 0;
}
else{
temp += height[i];
}
}
return result;
}
};
3 标准解
3.1 分析
每个位置i能存储的水量是由i左侧最高的板块和i右侧最高的板块共同决定的,即water[i] = min(left_max[i],right_max[i])-height[i]
从左向右遍历,记录每个位置的左侧最高板块,从右向左遍历,记录每个位置的右侧最高板块。
3.2 代码
class Solution {
public:
int trap(vector<int>& height) {
if(!height.size())
return 0;
vector<int> left(height.size(),0),right(height.size(),0);
int result = 0;
for(int i = 0; i < height.size(); i++){
left[i] = max((i>0?left[i-1]:0),height[i]);
}
for(int i = height.size()-1; i >=0; i--){
right[i] = max((i<height.size()-1?right[i+1]:0),height[i]);
}
for (int i = 1; i < height.size() - 1; i++) {
result += min(left[i], right[i]) - height[i];
}
return result;
}
};