Leetcode 42. Trapping Rain Water
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
解题思路
数组的每一个位置是否可以储水,需要看这个位子左边和右边最高的两根柱子,并且储水量取决于两个柱子中较短的那一根。
第一种思路:维护两个数据,第一个maxLeftArray记录下每一个位置左边最高的柱子的高度,第二个maxRightArray记录下每一个位置右边最高的柱子的高度。重新遍历原数组height,计算储水量: : water += min(maxLeftArray[i], maxRightArray[i]) - height[i] > 0 ? min(maxLeftArray[i], maxRightArray[i]) - height[i] : 0
第二种改进思路:不需要提前计算维护左边和右边最大值数组,只需要维护两个值,maxLeft和maxRight,以及两个左右指针i,j,但是需要从两边往里计算。先假设左右两边的柱子是最大的,然后从maxLeft和maxRight中较小的那一边开始计算,(第一,储水量取决于较短的那一根,第二,因为另一边的柱子更高,可以保证水肯定可以储存住的),计算完之后更新 i 和 maxLeft 或者 j 和 maxRight。
Python代码
class Solution(object):
def trap(self, height):
"""
:type height: List[int]
:rtype: int
"""
water = 0
if len(height) <= 0: # 考虑为空的情况
return water
i = 1
j = len(height)-2
maxl = height[0]
maxr = height[len(height)-1]
while i <= j:
if maxl <= maxr: # 从最外围开始记录最高的柱子,并且从小的一端计算,确保里面的水都能留住
water += max(0, maxl - height[i])
maxl = max(maxl, height[i])
i += 1
else:
water += max(0, maxr - height[j])
maxr = max(maxr, height[j])
j -= 1
return water
思路2
单调递减栈
需要找到左边递减,右边递增的V型结构,可以维护一个栈,如果当前的柱子小于栈顶,入栈,如果当前柱子大于栈顶,就找到了一个可以储水的V型池,并且计算储水量,接着继续和栈顶比较,如果仍然大于栈顶,仍然是V型池,否则就入栈。
计算储水量有一个小trick,每一次的栈顶柱子,就是水位最低的位置,更低的空都被水填满了,之前计算过了;所以就相当于一个平底的池子,水深就是两边高度较短的减去栈顶柱子的高度,储水宽度就是两边柱子的距离。
C++ 代码
class Solution {
public:
int trap(vector<int>& height) {
int water = 0, curr = 0;
if(height.size() <= 0 ) return water;
stack<int> barStack;
while(curr < height.size()) {
while(!barStack.empty() && (height[curr] > height[barStack.top()]) ){
int top = barStack.top();
barStack.pop();
if(barStack.empty()) break;
water += (min(height[barStack.top()],height[curr]) - height[top] ) * (curr - barStack.top() - 1); // 储水量等于水深度 * 水宽度
}
barStack.push(curr++);
}
return water;
}
};