Leetcode 42. Trapping Rain Water

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;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值