LeetCode - Trap Rain Water

这道题思维很巧妙,不管是two pointer方法,还是stack方法,能想出来的都太厉害了!

首先,two pointer两遍扫描,对于每个位置来说,找到它左右最高的bar,那么当前位置能储存的水量就是两边最高bar较小那个的值-自己的值,代码如下:

public int trap(int[] A){
        if(A==null ||A.length==0) return 0;
        int trap = 0;
        int[] lmax = new int[A.length];
        int[] rmax = new int[A.length];
        lmax[0]=0;
        for(int i=1; i<A.length; i++){
            lmax[i] = Math.max(A[i-1],lmax[i-1]);
        }
        rmax[A.length-1]=0;
        for(int i=A.length-2; i>=0; i--){
            rmax[i] = Math.max(rmax[i+1],A[i+1]);
        }
        
        for(int i=0; i<A.length; i++){
            int tmp = Math.min(lmax[i],rmax[i])-A[i];
            if(tmp>0) trap+=tmp;
        }
        return trap;
    }

另外一种DP只需要一遍扫描,即一个指针从左往右扫,一个指针从右往左扫,那边值小哪边就是装水的限制,所以值小的那边继续扫,直到扫到比初始的限制值大为止,扫的过程中记录每个位置能装水的数量,直到两个指针相遇:

    public int trap(int[] A){
        if(A==null ||A.length==0) return 0;
        int trap = 0;
        int start = 0;
        int end = A.length-1;
        while(start<end){
            if(A[start]<=A[end]){
                int tmp = A[start];
                while(A[start]<=tmp){
                    trap+= tmp-A[start];
                    start++;
                    if(start==end) return trap;
                }
            }
            else if(A[start]>A[end]){
                int tmp = A[end];
                while(A[end]<=tmp){
                    trap+= tmp-A[end];
                    end--;
                    if(start==end) return trap;
                }
            }
        }
        return trap;
    }

刚看到这道题的时候,就觉得应该用stack,但想了半天也没想出来正确的计算方法,还是看的答案,简洁的代码和解释见:
http://n00tc0d3r.blogspot.com/2013/06/trapping-rain-water.html

下面是我重写的代码:

    public int trap(int[] A) {
        Stack<Integer> bar = new Stack<Integer>();
        int trap = 0;
        for(int i=0; i<A.length; i++){
            if(bar.size()==0) bar.push(i);
            else{
                if(A[i]<=A[bar.peek()]){
                    bar.push(i);
                }
                else{
                    while(bar.size()!=0 && A[bar.peek()]<A[i]){
                        int tmp = bar.pop();
                        if(bar.empty()) break;
                        trap += (Math.min(A[i],A[bar.peek()])-A[tmp])*(i-bar.peek()-1);
                    }
                    bar.push(i);
                }
                
            }
        }
        return trap;
    }

没有原代码简洁,不过好歹自己按思路写一遍,更能记得住。

总结:这种和两边值有关的题都可以用两边扫描的方法,另外用stack也可以存储左边的值,等找到合适的右边值后再回到stack中看左边的值。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值