leetcode 42 Trapping Rain Water

来源:互联网 发布:菜鸟网络是做什么的 编辑:程序博客网 时间:2024/05/16 14:02

Trapping Rain Water
Total Accepted: 47928 Total Submissions: 158168 Difficulty: Hard

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!

这道题我目前知道两种算法,第一种是我自己想的,效率不高,测试时间是24ms,第二种是别人的做法,效率较高,测试时间是4ms。

首先,记录一下我自己的解法,首先如果一个地方能蓄水那么它的左右两侧必然有比它高的两根杆(姑且称直方图中的竖直矩形为杆),所以我用两个变量firstHeight和secondHeight来记录这两根杆的长度,并且用firstIndex和secondIndex来记录它们对应在数组中的位置。我发现这样的两根杆满足一个条件,就是它们比与它相邻的下一根杆要高,否则,就应该选下一根杆而非这根杆作为蓄水的左右两根杆。这听上去是对的,但是事实却并非完全如此,例如:
这里写图片描述
如果按我们的描述,我们就应该选择用红线圈出来的两根杆,而事实上我们并不是使用右边最高的那根杆作为蓄水的杆,而是使用了它左边的那根杆作为蓄水的杆,这样一来我们之前描述的算法就不能用了,其实只要一点点改进,这个算法照样行得通。

这个改进稍后再讲,现在我们仍然使用原来的算法,那么我们选择的左右两根杆就是图中红线圈出来的杆。它们之间可以蓄水的最大体积,就等于它们两者中较矮的那个的高度乘以两者间的距离,即如图中的绿色部分。
这里写图片描述
显然这个部分比真实的部分大,那么我们就要减去多加的部分,我们就用较小的那根杆的高度去减去,两杆之间的其他每根杆的高度,把这些差相加得到的结果就是多加的高度。但这有个问题,就是但我们有较小的那根杆去减最高的那根杆的左边那根杆时,结果为负数,此时就不能再将结果直接相加了,就要用到我之前说的那个改进,其实很简单,对于这种结果为负的情况,直接忽略,不进行相减操作,其实不难理解,因为在这根杆的位置不会蓄水。经过这样的操作之后,左右两根杆之间蓄水的体积就计算出来了,此时我们就要找到下一组杆,再算它们之间的蓄水体积。那么谁会是下一组杆呢?这会有两种情况:
这里写图片描述这里写图片描述
我们会发现,下一组杆的左杆的选择的实际上是前一组左右杆中的较高的那个。其实到这步之后,我们不断重复上述过程,就可以总的蓄水体积了。但有两点要注意:1. 对于上述的第二种情况,如图红色的部分已经计算过了,如果直接使用上面描述的算法,红色部分就会被再计算一次,为了避免这个错误,我们在第一次计算的过程中,边计算变把坑填平,即如图所示,这样在使用原来算法时,就不会重复计算已经算过的部分了。
这里写图片描述这里写图片描述 2. 我们原始的算法是取每一个比与它相邻的下一根杆要高的杆作为蓄水的两根杆之一来进行计算,但这样实际上产生了很多不必要的计算,如图
这里写图片描述
图中每个红线圈起来的杆都会作为蓄水的杆的右杆然后代入到算法中进行计算,但实际上后面3个杆的计算是不必要的因为第一个杆算完之后就已经填平了,如图,两杆之间部分的高度都高于右杆,因此无法蓄水,所以总的体积不变。
这里写图片描述
因此,我们应该改进这一条件,我们发现真正蓄水的杆不仅是比与它相邻的下一根杆要高,同时比与它相邻的上一根杆也要高,但添加了这一条件后,计算的后3根杆,都不在满足条件,从而不需要考虑了,简化的计算。根据我提交的结果来看,原始算法为32ms,根据这点改进后为24ms。
下面是算法代码:

int trap(int* height, int heightSize) {    int firstHeight = height[0], secondHeight = height[0];    int firstIndex = 0, secondIndex = 0;    int sum = 0;    for(int i = 1; i < heightSize; i++)    {        if(height[i] > height[i-1])        {            if(i < heightSize - 1 && height[i+1] > height[i])                continue;            secondHeight = height[i];            secondIndex = i;            int newheight = secondHeight < firstHeight ? secondHeight : firstHeight;            for(int j = firstIndex+1; j < secondIndex; j++)            {                 if(newheight - height[j] > 0)                {                    sum += newheight - height[j];                    height[j] = newheight;                }            }            if(secondHeight >= firstHeight)            {                firstHeight = secondHeight;                firstIndex = secondIndex;            }        }    }    return sum;}

另外一种别人的方法更简单,从左往右走,记录当前遇到杆的最高值,如果当前的杆的高度小于最高值,就把最高值与它的差作为蓄水量进行累加,这样累加结果会有一个误差,就是所有根据全部杆最高值进行累计的值,实际上是不存在的(除非最高值在最后一根杆)。如图
这里写图片描述这里写图片描述
如图中绿色部分就是多累加的部分,要扣除这部分也很简单,方法跟前面类似,不过是从后往前走,记录当前遇到的杆的最大值,这个最大值和所有杆的最高杆的高度之差就是我们每根杆要扣除的值,对每根杆计算这个扣除值直到遇到所有杆的最高杆,整个扣除过程结束,此时剩下的累计值就是我们要求的总的蓄水量。

程序完整代码如下:

int trap(int* height, int heightSize) {    int sum = 0;    int maximum = height[0];    for(int i = 0; i < heightSize; i++)    {        if(maximum < height[i])            maximum = height[i];        sum += maximum - height[i];    }    int max2 = height[heightSize - 1];    for(int i = heightSize - 1; i >= 0; i--)    {        if(height[i] == maximum)            break;        if(max2 < height[i])            max2 = height[i];        sum -= maximum - max2;    }    return sum;}int main(){    int heightSize;    cout<<"Input the size of height:"<<endl;    cin>>heightSize;    int *height = (int*)malloc(sizeof(int) * heightSize);    for(int i = 0; i < heightSize; i++)    {        scanf("%d,", &height[i]);    }    cout<<trap(height, heightSize)<<endl;}
0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 苹果6s手机弯了怎么办 苹果手机变弯了怎么办 苹果手机屏幕摔碎了怎么办 苹果6p后壳弯曲怎么办 苹果手机后壳有点弯曲怎么办 苹果手机x弯了怎么办 苹果8手机弯了怎么办 苹果8p手机弯了怎么办? 美版iphone弯了怎么办 oppor9手机听筒声音小怎么办 苹果7摔弯了屏幕怎么办 苹果手机压弯了怎么办 京东买的电脑坏了怎么办 拼多多低价乱价怎么办 厂家不通过经销商直接发货怎么办 媳妇吵架说我全家有病怎么办 全家都不尊重媳妇怎么办 招商闪电贷有额度不通过怎么办 闪电贷页面登录不进去怎么办 91借钱极速逾期怎么办 论文没过拿不到毕业证怎么办 大学论文不过拿不到毕业证怎么办 转店被黑中介骗了钱怎么办? 被星外转铺骗了怎么办 店铺转了后悔了怎么办 商铺转让不出去怎么办? 和包券密码丢失怎么办 天猫购物卷兑换不了怎么办 淘宝新店每天只有几个访客怎么办 注册淘宝企业店铺需要审核怎么办 淘宝店铺被投诉知识产权怎么办 一般违规扣48分怎么办 金税盘处于报税期不能开票怎么办 小规模税率开错了怎么办 我是代购卖家被买家投诉偷税怎么办 天猫盒子内存不够怎么办 天猫品牌申请不通过怎么办 天猫商家发货发个空包裹怎么办 无限流量怎么办没有4g 海外直邮身份证过期了怎么办 买车的人不过户怎么办