42 Trapping Rain Water

16 篇文章 0 订阅
14 篇文章 0 订阅

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;
    }
};

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值