LeetCode - Trap Rain Water

来源:互联网 发布:中南大学怎么样 知乎 编辑:程序博客网 时间:2024/06/03 21:50

这道题思维很巧妙,不管是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
原创粉丝点击