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.
For example,
Given [0,1,0,2,1,0,1,3,2,1,2,1], return 6.
![]()
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!
2. 解题思路
我们的基本思路呢, 就是找到这个数组从左向右递增的的位置, 同时找到从右向左的递增位置, 然后根据这些递增位置之间所形成的区间, 计算存储的水的量的多少。
3. code
class Solution {
public:
int trap(vector<int>& height) {
if (height.size() <= 1)
return 0;
// 找到递增 与 递减的关键节点
vector<int> incr_pos_l, incr_pos_r;
int mymax = 0;
for (int i = 0; i != height.size(); i++){
if (height[i] > mymax){
incr_pos_l.push_back(i);
mymax = height[i];
}
}
mymax = 0;
for (int i = height.size() - 1; i >= 0; i--){
if (height[i] > mymax){
incr_pos_r.push_back(i);
mymax = height[i];
}
}
// 计算水容量
int voll = computeVal(incr_pos_l, height, true);
int volr = computeVal(incr_pos_r, height, false);
int val = 0;
for (int j = incr_pos_l.back(); j != incr_pos_r.back(); j++){
val += height[incr_pos_l.back()] - height[j];
}
return voll + volr + val;
}
private:
void myincr(int & i, bool isLeft){
isLeft ? i++ : i--;
}
int computeVal(vector<int> incr_pos, vector<int>& height, bool isLeft){
int sum = 0;
for (int i = 0; i < incr_pos.size() - 1; i++){
int val = 0;
for (int j = incr_pos[i]; j != incr_pos[i + 1]; myincr(j, isLeft)){
val += height[incr_pos[i]] - height[j];
}
sum += val;
}
return sum;
}
};
4. 大神解法
4.1 demo1 两端逼近
两端逼近, 找到他们两端的所记录到的最大值, 并计算存储的水量
Keep track of the maximum height from both forward directions backward directions, call them leftmax and rightmax.
public int trap(int[] A){
int a=0;
int b=A.length-1;
int max=0;
int leftmax=0;
int rightmax=0;
while(a<=b){
leftmax=Math.max(leftmax,A[a]);
rightmax=Math.max(rightmax,A[b]);
if(leftmax<rightmax){
max+=(leftmax-A[a]); // leftmax is smaller than rightmax, so the (leftmax-A[a]) water can be stored
a++;
}
else{
max+=(rightmax-A[b]);
b--;
}
}
return max;
}
4.2 demo2
Keep track of the already safe level and the total water so far. In each step, process and discard the lower one of the leftmost or rightmost elevation.
C
Changing the given parameters to discard the lower border. I'm quite fond of this one.
int trap(int* height, int n) {
int level = 0, water = 0;
while (n--) {
int lower = *height < height[n] ? *height++ : height[n];
if (lower > level) level = lower;
water += level - lower;
}
return water;
}
Slight variation with two pointers (left and right).
int trap(int* height, int n) {
int *L = height, *R = L+n-1, level = 0, water = 0;
while (L < R) {
int lower = *L < *R ? *L++ : *R--;
if (lower > level) level = lower;
water += level - lower;
}
return water;
}
C++
With left and right index.
int trap(vector<int>& height) {
int l = 0, r = height.size()-1, level = 0, water = 0;
while (l < r) {
int lower = height[height[l] < height[r] ? l++ : r--];
level = max(level, lower);
water += level - lower;
}
return water;
}
With left and right iterator.
int trap(vector<int>& height) {
auto l = height.begin(), r = height.end() - 1;
int level = 0, water = 0;
while (l != r + 1) {
int lower = *l < *r ? *l++ : *r--;
level = max(level, lower);
water += level - lower;
}
return water;
}