You are given a m x n 2D grid initialized with these three possible values. -1 - A wall or an obstacle. 0 - A gate. INF - Infinity means an empty room. We use the value 231 - 1 = 2147483647 to represent INF as you may assume that the distance to a gate is less than 2147483647. Fill each empty room with the distance to its nearest gate. If it is impossible to reach a gate, it should be filled with INF. For example, given the 2D grid: INF -1 0 INF INF INF INF -1 INF -1 INF -1 0 -1 INF INF After running your function, the 2D grid should be: 3 -1 0 1 2 2 1 -1 1 -1 2 -1 0 -1 3 4
实际上就是找每个房间到最近的门的距离,我们从每个门开始,广度优先搜索并记录层数就行了。如果某个房间之前被标记过距离,那就选择这个距离和当前距离中较小的那个。这题要注意剪枝,如果下一步是门或者下一步是墙或者下一步已经访问过了,就不要加入队列中。否则会超时。
1 public class Solution { 2 int[][] dir = new int[][]{{-1,0},{1,0},{0,-1},{0,1}}; 3 4 public void wallsAndGates(int[][] rooms) { 5 if (rooms==null || rooms.length==0 || rooms[0].length==0) return; 6 int m = rooms.length; 7 int n = rooms[0].length; 8 for (int i=0; i<m; i++) { 9 for (int j=0; j<n; j++) { 10 if (rooms[i][j] != 0) continue; 11 LinkedList<Integer> queue = new LinkedList<Integer>(); 12 boolean[][] visited = new boolean[m][n]; 13 queue.offer(i*n + j); 14 visited[i][j] = true; 15 int pNum = 1; 16 int cNum = 0; 17 int level = 0; 18 while (!queue.isEmpty()) { 19 int cur = queue.poll(); 20 int row = cur/n; 21 int col = cur%n; 22 pNum--; 23 for (int[] d : dir) { 24 int x = row + d[0]; 25 int y = col + d[1]; 26 if (x>=0 && x<m && y>=0 && y<n && !visited[x][y] && rooms[x][y]!=0 && rooms[x][y]!=-1) { 27 rooms[x][y] = Math.min(rooms[x][y], level+1); 28 queue.offer(x*n+y); 29 visited[x][y] = true; 30 cNum++; 31 } 32 } 33 if (pNum == 0) {//finish this level 34 level++; 35 pNum = cNum; 36 cNum = 0; 37 } 38 } 39 } 40 } 41 } 42 }
BFS 还有一种写法,就是不用pNum, cNum两个variables, 而记录每一次queue的size,然后poll() size那么多次,其实本质是一样的
1 public class Solution { 2 public void wallsAndGates(int[][] rooms) { 3 if(rooms.length == 0) return; 4 for(int i = 0; i < rooms.length; i++){ 5 for(int j = 0; j < rooms[0].length; j++){ 6 // 如果遇到一个门,从门开始广度优先搜索,标记连通的节点到自己的距离 7 if(rooms[i][j] == 0) bfs(rooms, i, j); 8 } 9 } 10 } 11 12 public void bfs(int[][] rooms, int i, int j){ 13 Queue<Integer> queue = new LinkedList<Integer>(); 14 queue.offer(i * rooms[0].length + j); 15 int dist = 0; 16 // 用一个集合记录已经访问过的点 17 Set<Integer> visited = new HashSet<Integer>(); 18 visited.add(i * rooms[0].length + j); 19 while(!queue.isEmpty()){ 20 int size = queue.size(); 21 // 记录深度的搜索 22 for(int k = 0; k < size; k++){ 23 Integer curr = queue.poll(); 24 int row = curr / rooms[0].length; 25 int col = curr % rooms[0].length; 26 // 选取之前标记的值和当前的距离的较小值 27 rooms[row][col] = Math.min(rooms[row][col], dist); 28 int up = (row - 1) * rooms[0].length + col; 29 int down = (row + 1) * rooms[0].length + col; 30 int left = row * rooms[0].length + col - 1; 31 int right = row * rooms[0].length + col + 1; 32 if(row > 0 && rooms[row - 1][col] > 0 && !visited.contains(up)){ 33 queue.offer(up); 34 visited.add(up); 35 } 36 if(col > 0 && rooms[row][col - 1] > 0 && !visited.contains(left)){ 37 queue.offer(left); 38 visited.add(left); 39 } 40 if(row < rooms.length - 1 && rooms[row + 1][col] > 0 && !visited.contains(down)){ 41 queue.offer(down); 42 visited.add(down); 43 } 44 if(col < rooms[0].length - 1 && rooms[row][col + 1] > 0 && !visited.contains(right)){ 45 queue.offer(right); 46 visited.add(right); 47 } 48 } 49 dist++; 50 } 51 } 52 }