【leetcode】Trapping Rain Water

参考解法
题目

这道题一共有两种思路,四个解法

思路一:
一列一列计算,对于每一列我们都计算一下上面可以放多少水,基本思路就是找一下左边最高的柱子,找一下右边最高的柱子,取最小值减去这一列柱子高度,即为在这一列上可以放多少水。

解法一:
两次dp遍历,一次找左边的最大值,一次找右边的最大值

int trap(vector<int>& height) {
        int n=height.size();
        vector<int> dp(n,0);
        int mn=0;
        int i;
        for(i=0;i<n;i++)
        {
            dp[i]=mn;
            mn=max(mn,height[i]);
        }
        int ans=0;
        mn=0;
        int edge;
        for(i=n-1;i>=0;i--)
        {
            edge=min(mn,dp[i]);
            if(edge>height[i])  ans+=edge-height[i];
            mn=max(mn,height[i]);
        }
        return ans;
    }

解法二:
只需要一次遍历即可。需要两个指针一个从左向右,一个从右向左,选取指向柱子中较小的那一个并从那一边从另一边扫描,选取比它小的柱子,计算这些柱子上面可以存储的水。因为是从两边开始扫描的,所以能确定一边肯定是最大值,另一边比最大值大即可,我们并不关心另一边的最大值时多少,反正都是要在两个最大值中取一个较小值的。

int trap(vector<int>& height){
        int n=height.size();
        int i=0,j=n-1;
        int ans=0;
        int mn;
        while(i<j)
        {
            mn=min(height[i],height[j]);
            if(mn==height[i])
            {
                i++;
                while(height[i]<mn&&i<j)
                {
                    ans+=mn-height[i];
                    i++;
                }
            }
            else
            {
                j--;
                while(height[j]<mn&&i<j)
                {
                    ans+=mn-height[j];
                    j--;
                }
            }
        }
        return ans;
    }

解法三:
思路和解法二一样,但是写起来更简洁一些
欣赏即可,我不习惯这么写

int trap(vector<int>& height) {
        int l = 0, r = height.size() - 1, level = 0, res = 0;
        while (l < r) {
            int lower = height[(height[l] < height[r]) ? l++ : r--];
            level = max(level, lower);
            res += level - lower;
        }
        return res;
    }

思路二:
用栈的思想来做,这个我是无论如何也想不出来的。
这个思路不再是一列一列算,而是按行算。
依次把每一列和栈顶元素比较,如果对应列小于栈顶坐标对应列或栈为空,无法积水,压入栈。如果大于,则弹出栈顶元素,如果此时为空,说明是边界,无法积水,否则可以积水。但是这里注意,不仅仅是两根柱子的高度差,还需要乘以他们间的距离。
举个例子,对于3,2,1,2,3。我们先计算了2,1,2中间面积为1的坑,然后是把1看成2,计算了3,2,2,2,3中面积为3的坑。

解法四:
这个解法里面有很多的注意点。首先一个i-s.top()-1中的1不要忘记减去,还有一个是这里用while循环而不用for循环是因为它需要循环判断,一是它不一定只做一个底的边,如4,1,2,3;3会和2,1都进行相同操作。而是边也有可能做底,如4,2,3,4;3做了2的边以后入栈,做了4的底。

int trap(vector<int>& height){
        stack<int> s;
        int n=height.size();
        int i=0;
        int ans=0;
        while(i<n)
        {
            if(s.empty()||height[s.top()]>=height[i])
                s.push(i++);
            else
            {
                int p=s.top();
                s.pop();
                if(!s.empty())  ans+=(min(height[i],height[s.top()])-height[p])*(i-s.top()-1);
            }
        }
        return ans;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值