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 2^31 - 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
.
Example
Given the 2D grid:
INF -1 0 INF
INF INF INF -1
INF -1 INF -1
0 -1 INF INF
return the result:
3 -1 0 1
2 2 1 -1
1 -1 2 -1
0 -1 3 4
Solution 1. O(m^2 * n^2) runtime, O(n * m) space
A straightforward way of solving this problem is to perform a bfs on all empty rooms(cell of value INF).
Take each empty room as the source point of level 0 and use a distance variable to keep track of the current traversal level.
If at certain level, a gate cell is first found, set the distance of the current source empty room to the nearest exit as the current distance value.
The runtime of this algorithm is O(n * m) * O(n * m) as there are n * m possible source points and each bfs takes O(n * m) time,
The space usage is O(n * m) as we need to keep track of which cells have been visited so that they'll not be visited again.
One note here: since this is the a multiple source problem and this algorithm changes its distance value one at a time. Extra care should be given
to make sure a previous bfs result does not affect the correctness of the next bfs.
If highlighted line 42 is changed to rooms[x][y] == Integer.MAX_VALUE, this algorithm will be incorrect. This is because a previous bfs may already
change one of the empty cell value from INF to some distance value. In the current bfs of the current source point, it should still be able to pass through
the previously changed empty cell even if its value is not INF anymore. So the check condition should be rooms[x][y] != - 1. As long as the neighboring cell
has not been visited before and it is not a wall, the algorithm should add it to the queue for future traversal.
1 public class Solution { 2 class Point { 3 int row; 4 int col; 5 Point(int r, int c) { 6 this.row = r; 7 this.col = c; 8 } 9 } 10 private int[] deltaX = {-1, 0, 1, 0}; 11 private int[] deltaY = {0, 1, 0, -1}; 12 public void wallsAndGates(int[][] rooms) { 13 if(rooms == null || rooms.length == 0 || rooms[0].length == 0) { 14 return; 15 } 16 for(int r = 0; r < rooms.length; r++) { 17 for(int c = 0; c < rooms[0].length; c++) { 18 if(rooms[r][c] == Integer.MAX_VALUE) { 19 bfs(rooms, r, c); 20 } 21 } 22 } 23 } 24 private void bfs(int[][] rooms, int row, int col) { 25 Queue<Point> queue = new LinkedList<Point>(); 26 boolean[][] visited = new boolean[rooms.length][rooms[0].length]; 27 queue.add(new Point(row, col)); 28 visited[row][col] = true; 29 int distance = 1; 30 31 while(!queue.isEmpty()) { 32 int size = queue.size(); 33 for(int i = 0; i < size; i++) { 34 Point currPoint = queue.poll(); 35 for(int dir = 0; dir < 4; dir++) { 36 int x = currPoint.row + deltaX[dir]; int y = currPoint.col + deltaY[dir]; 37 if(isInBound(rooms, x, y) && !visited[x][y]) { 38 if(rooms[x][y] == 0) { 39 rooms[row][col] = distance; 40 return; 41 } 42 else if(rooms[x][y] != -1){ 43 queue.add(new Point(x, y)); 44 visited[x][y] = true; 45 } 46 } 47 } 48 } 49 distance++; 50 } 51 } 52 private boolean isInBound(int[][] rooms, int row, int col) { 53 return (row >= 0 && row < rooms.length) && (col >= 0 && col < rooms[0].length); 54 } 55 }
Solution 2. O(n * m) runtime, O(n * m) space
If there is only one gate, then the problem is a multiple sources single destination problem. Since the distance from an empty room to a gate
is the same with the distance from the same gate to the same empty room. We can convert it to a single source multiple destinations problem:
Find all the shortest distances from one single gate to all the empty rooms. Since the distance is measured in unit cell distance, we can use
BFS to solve this problem in O(n * m) time.
The original problem can have multiple gates, which is a multiple sources multiple destinations problem.
We can treate all the gates as one big source, and start the bfs at the same time from this big source(start bfs from all gates at the same time).
If any gate in this big source reaches an empty room first, the shortest distance from an empty room to any gate is established. Later traversals
on the same empty room from other gates are simply ignored as there is already a shorter path from this empty room to another gate. All other
unvisited empty rooms that can be connected with the current empty room can acheive a shorter distance to a gate by using the current empty room's
shortest path to a gate.
1 public class Solution { 2 class Point { 3 int row; 4 int col; 5 Point(int r, int c) { 6 this.row = r; 7 this.col = c; 8 } 9 } 10 public void wallsAndGates(int[][] rooms) { 11 if(rooms == null || rooms.length == 0 || rooms[0].length == 0) { 12 return; 13 } 14 int n = rooms.length; 15 int m = rooms[0].length; 16 int[] deltaX = {-1, 0, 1, 0}; 17 int[] deltaY = {0, 1, 0, -1}; 18 Queue<Point> queue = new LinkedList<Point>(); 19 for(int i = 0; i < n; i++) { 20 for(int j = 0; j < m; j++) { 21 if(rooms[i][j] == 0) { 22 queue.add(new Point(i, j)); 23 } 24 } 25 } 26 while(!queue.isEmpty()) { 27 Point currPoint = queue.poll(); 28 for(int dir = 0; dir < 4; dir++) { 29 int x = currPoint.row + deltaX[dir]; 30 int y = currPoint.col + deltaY[dir]; 31 if(isInBound(rooms, x, y)) { 32 if(rooms[x][y] == Integer.MAX_VALUE) { 33 rooms[x][y] = rooms[currPoint.row][currPoint.col] + 1; 34 queue.add(new Point(x, y)); 35 } 36 } 37 } 38 } 39 } 40 private boolean isInBound(int[][] rooms, int row, int col) { 41 return (row >= 0 && row < rooms.length && col >= 0 && col < rooms[0].length); 42 } 43 }
Related Problems
Number of Islands
Surrounded Regions
Build Post Office
Build Post Office II