lintcode573- Build Post Office II- hard
Given a 2D grid, each cell is either a wall 2
, an house 1
or 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.
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.)
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