1. 程式人生 > >leetcode 407. Trapping Rain Water II

leetcode 407. Trapping Rain Water II


Given an m x n matrix of positive integers representing the height of each unit cell in a 2D elevation map, compute the volume of water it is able to trap after raining.

 

Note:

Both m and n are less than 110. The height of each unit cell is greater than 0 and is less than 20,000.

 

Example:

Given the following 3x6 height map:
[
  [1,4,3,1,3,2],
  [3,2,1,3,2,4],
  [2,3,3,2,3,1]
]

Return 4.

The above image represents the elevation map [[1,4,3,1,3,2],[3,2,1,3,2,4],[2,3,3,2,3,1]] before the rain.

 

After the rain, water is trapped between the blocks. The total volume of water trapped is 4.


思路:由Trapping Rain Water二維問題的其中一種解法想到,可以從邊緣開始下手。把邊緣的點放入一個PriorityQueue。然後由最小的點開始BFS,如果BFS到的點如果小於PriorityQueue中的最小值,放入一個Queue裡面,可以直接求出此點的容量。如果BFS到的點大於PriorityQueue中的最小值,則把此點放入PriorityQueue,作為之後的邊緣點。

class Solution {
    class Point{
        int x;
        int y;
        Point(int x,int y){
            this.x=x;
            this.y=y;
        }
    }
    public int trapRainWater(int[][] heightMap) {
        if(heightMap==null||heightMap.length<=2||heightMap[0].length<=2) return 0;
        PriorityQueue<Point> pq=new PriorityQueue<>(new Comparator<Point>(){
            public int compare(Point p1,Point p2){
                return heightMap[p1.x][p1.y]-heightMap[p2.x][p2.y];
            }
        });
        LinkedList<Point> queue=new LinkedList<>();
        boolean[][] visited=new boolean[heightMap.length][heightMap[0].length];
        for(int j=0;j<heightMap[0].length;j++) pq.offer(new Point(0,j));
        for(int j=0;j<heightMap[0].length;j++) pq.offer(new Point(heightMap.length-1,j));
        for(int i=1;i<heightMap.length-1;i++) pq.offer(new Point(i,0));
        for(int i=1;i<heightMap.length-1;i++) pq.offer(new Point(i,heightMap[0].length-1));
        int[][] dir={{0,1},{0,-1},{1,0},{-1,0}};
        int count=0;
        while(pq.size()>0){
            queue.add(pq.peek());//基於pq的最小值的一次BFS
            while(queue.size()>0){
                Point p=queue.poll();
                for(int i=0;i<4;i++){
                    int x=p.x+dir[i][0];
                    int y=p.y+dir[i][1];
                    if(x<1||x>=heightMap.length-1||y<1||y>=heightMap[0].length-1||visited[x][y]){
                        continue;
                    } 
                    visited[x][y]=true;
                    if(heightMap[x][y]>heightMap[pq.peek().x][pq.peek().y]){
                        pq.offer(new Point(x,y));//記錄大於,之後最為邊緣點
                    }else{
                        queue.add(new Point(x,y));//記錄小於,直接求出容量
                        count+=heightMap[pq.peek().x][pq.peek().y]-heightMap[x][y];
                    }
                }
            }    
            pq.poll();
        }
        return count;
    }
}

討論區有個做法不需要Queue。思路是用Point中記錄高度,對於小於當前高度的點,用當前高度代替,再加到優先佇列就可以了。

https://leetcode.com/problems/trapping-rain-water-ii/discuss/89461/Java-solution-using-PriorityQueue