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
實際上就是找每一個房間到最近的門的距離,咱們從每一個門開始,廣度優先搜索並記錄層數就好了。若是某個房間以前被標記過距離,那就選擇這個距離和當前距離中較小的那個。這題要注意剪枝,若是下一步是門或者下一步是牆或者下一步已經訪問過了,就不要加入隊列中。不然會超時。less
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那麼屢次,其實本質是同樣的this
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 }