1. 程式人生 > >lintcode573- Build Post Office II- hard

lintcode573- Build Post Office II- hard

坐標 logs offer 變量 ice poll ive spa 地圖

Given a 2D grid, each cell is either a wall 2, an house 1or empty 0 (the number zero, one, two), find a place to build a post office so that the sum of the distance from the post office to all the houses is smallest.

Return the smallest sum of distance. Return -1 if it is not possible.

Notice
  • You cannot pass through wall and house, but can pass through empty.
  • You only build post office on an empty.
Example

Given a grid:

0 1 0 0 0
1 0 0 2 1
0 1 0 0 0

return 8, You can build at (1,1). (Placing a post office at (1,1), the distance that post office to all the house sum is smallest.)

Challenge

Solve this problem within O(n^3) time.

之前題目 I 是可以直接算manhattan距離,這裏不行,距離要用BFS算了。

算法主體:1.找出所有house放list 2.遍歷house做bfs,把距離之和distSum[][]以及空地訪問次數visitCnt[][]記錄下來. 3.根據visitCnt[][]遍歷合格的房子都走得到的空地,訪問distSum[][]打擂臺決出最小dist。

算法BFS:size的層級遍歷。參數傳入distSum[][]和visitCnt[][]讓所有的BFS能共享這個"全局變量"進行修改。從1出發,BFS出所有的0,每次對0訪問次數計數++,層級遍歷的step表示從1出發到這個0的距離,讓distSum[][]+=steps。另外坐標Point(x,y)這種數據結構不能用HashSet作為和queue搭配的去重set,這時候可以巧妙地自己命名一個boolean[][] hash,如果某個坐標(x,y)被加入queue了,以後不想讓這個點被重復加,就賦值hash[x][y] = true; 起到了set的作用。

數據結構:distSum[][] 保存了對於地圖中某個空地0,到所有房子1的距離和。 visitCnt[][] 保存了對於地圖中某個空地0,能訪問到多少個房子1。

細節:1.int WALL EMPTY HOUSE=1 這種常數定義放在大類Solution裏,這樣保證所有子函數也能訪問到這些標誌。2.小心全都是房子不能放置office的corner case

public class Solution {
    /*
     * @param grid: a 2D grid
     * @return: An integer
     */
    
    private class Point{
        public int x;
        public int y;
        public Point(int x, int y) {
            this.x = x;
            this.y = y;
        }
    }
    
    private int WALL = 2;
    private int HOUSE = 1;
    private int EMPTY = 0;
    
    public int shortestDistance(int[][] grid) {
        // write your code here
        if (grid == null || grid.length == 0 || grid[0].length == 0) {
            return -1;
        }
        

        int h = grid.length;
        int w = grid[0].length;
        
        int[][] visitCnt = new int[h][w];
        int[][] distSum = new int[h][w];
        List<Point> houses = new ArrayList<Point>();
        for (int i = 0; i < h; i++) {
            for (int j = 0; j < w; j++) {
                if (grid[i][j] == HOUSE) {
                    houses.add(new Point(i,j));
                }
            }
        }
        
        for (Point p : houses) {
            bfs(grid, p, visitCnt, distSum);
        }
        
        int minDist = Integer.MAX_VALUE;
        for (int i = 0; i < h; i++) {
            for (int j = 0; j < w; j++) {
                //!!!兩個條件
                if (grid[i][j] != EMPTY || visitCnt[i][j] != houses.size()) {
                    continue;
                }
                minDist = Math.min(minDist, distSum[i][j]);
            }
        }
        
        // !!!CORNER CASE : all 1 or 2
        if (minDist == Integer.MAX_VALUE) {
            return -1;
        }
        return minDist;
    }
    
    private void bfs (int[][] grid, Point crt, int[][] visitCnt, int[][] distSum) {
        int[] dx = {-1, 0, 1, 0};
        int[] dy = {0, -1, 0, 1};
        boolean[][] hash = new boolean[grid.length][grid[0].length];
        Queue<Point> queue = new LinkedList<Point>();
        
        queue.offer(crt);
        hash[crt.x][crt.y] = true;
        int steps = 0;
        while (!queue.isEmpty()) {
            int size = queue.size();
            for (int i = 0; i < size; i++) {
                Point p = queue.poll();
                visitCnt[p.x][p.y]++;
                distSum[p.x][p.y] += steps;
                for (int dirct = 0; dirct < 4; dirct++) {
                    Point next = new Point (p.x + dx[dirct], p.y + dy[dirct]);
                    // !!!三個條件不要漏
                    if (isValid(grid, next) && !hash[next.x][next.y] && grid[next.x][next.y] == EMPTY) {
                        queue.offer(next);
                        hash[next.x][next.y] = true;
                    }
                }
            }
            steps++;
        }
        
    }
    
    private boolean isValid(int[][] grid, Point point) {
        int h = grid.length;
        int w = grid[0].length;
        return point.x >= 0 && point.x < h && point.y >= 0 && point.y < w;
    }
}

lintcode573- Build Post Office II- hard