https://www.nowcoder.com/questionTerminal/31c1aed01b394f0b8b7734de0324e00f
给定一个整形数组arr,已知其中所有的值都是非负的,将这个数组看作一个柱子高度图,计算按此排列的柱子,下雨之后能接多少雨水。
备注:
题解一:
双指针left,right分别从两边向中间遍历,找到每个水洼的边界。
在每一次循环中,从左向右遍历,当右边的高度小于当前左边界的高度时,这个位置上可以接水,累加接水量。当右边的高度大于当前左边界的高度时,更新左边界高度,将左指针left更新为当前位置。
从右向左遍历时,相同方法更新右边界高度,并在左边高度大于右边界高度时将右指针right位置不断向左更新。
当left和right位置重合或相邻时循环停止。
class Solution {
public:
/**
* max water
* @param arr int整型vector the array
* @return long长整型
*/
long long maxWater(vector<int>& arr) {
// write code here
int lh, rh, len, left, right;
long long water=0, lsum=0, rsum=0;
len = arr.size();
lh = arr[0];
rh = arr[len - 1];
left = 0;
right = len-1;
while(right - left > 1){
for(int i = left+1 ; i <= right ; i++){
while(arr[i] == lh && i - left == 1){
lsum = 0;
left = i;
lh = arr[i];
i++;
}
if(arr[i] < lh) lsum += arr[i];
else{
if(i - left > 1) water += 1LL * (i - left - 1) * lh - lsum;
lsum = 0;
left = i;
lh = arr[i];
break;
}
}
for(int i = right-1 ; i >= left ; i--){
while(arr[i] == rh && right - i == 1){
rsum = 0;
right = i;
rh = arr[i];
i--;
}
if(arr[i] < rh) rsum += arr[i];
else{
if(right - i > 1) water += 1LL * (right - i - 1) * rh - rsum;
rsum = 0;
right = i;
rh = arr[i];
break;
}
}
}
return water;
}
};
题解二:单调栈
单调栈介绍:https://www.zhihu.com/tardis/sogou/art/26465701
用单调栈从前到后维护每一个柱子,当一个柱子出栈时累加图中每一个矩形的面积。
k为当前栈顶的位置,i为当前准备入栈的位置,当第j根柱子被弹出栈时,计算矩形面积为(i-k-1) * ( min(arr[i],arr[k]) - arr[j] )
class Solution {
public:
/**
* max water
* @param arr int整型vector the array
* @return long长整型
*/
long long waterFromLeft(vector<int>& arr){
stack<int> s;
int j,k;
long long water = 0;
for(int i = 0 ; i < arr.size() ; i++){
while( !s.empty()){
if(arr[i] >= arr[s.top()]){
j = s.top();
s.pop();
if( !s.empty()){
k = s.top();
water += 1LL * (i-k-1) * ( min(arr[i],arr[k]) - arr[j] );
}
}
else break;
}
s.push(i);
}
return water;
}
long long maxWater(vector<int>& arr) {
// write code here
long long water = 0;
water = waterFromLeft(arr);
return water;
}
};