The problem
You are given an m*n
2D grid
initialized with these three possible values:
-1
- A wall or obstacle.0
- A gate.INF
- Infinity means an empty room. We use the value2^31 - 1 = 2147483647
to representINF
.
Fill each empty room with the distance to its nearest gate. If it’s impossible to reach the gate, it should be filled with INF
.
Assume the grid can only be traversed up, down, left, or right.
Modify the grid
in place.
Examples
Input: [
[2147483647,-1,0,2147483647],
[2147483647,2147483647,2147483647,-1],
[2147483647,-1,2147483647,-1],
[0,-1,2147483647,2147483647]
]
Output: [
[3,-1,0,1],
[2,2,1,-1],
[1,-1,2,-1],
[0,-1,3,4]
]
Input: [
[0,-1],
[2147483647,2147483647]
]
Output: [
[0,-1],
[1,2]
]
Constraints
- m == grid.length
- n == grid[i].length
- 1 <= m, n <= 100
- grid[i][j] is one of {-1, 0, 2147483647}
Explanation
From the description of the problem, we learn that we are given an m*n
grid where each position could have three possible values:
-1
that represents a wall0
that represents a gateINF
that represents an empty room
We also learned that we need to identify the nearest gate to the empty room (INF
) and replace it with the distance from the nearest gate to the empty room. If we can’t do that, we should fill it with INF
.
Now, let’s look at the first example:
- If we start from the top right cell and we are trying to determine how far away the gate is from the empty room, you can see that it’s only one position away from a gate. We can’t go up or right because those positions are out of bounds, and we can’t go down because we have a wall.
- If we start from the top left cell, we have three positions to the gate.
- If we start from the second row and second column and we are trying to find the distance to the
bottom left gate
, we will need three positions to get to this gate. - But if you look at the
third column
of thesecond row
, you can see that we have a gate with a closer distance of two.
The brute force way to solve this problem is to use a backtracking algorithm and find the distance for every single position of the entire grid. This solution will work but it will take O(mn4^(m*n)), which is not very efficient.
Breadth First Search Solution
func wallsAndGates(_ grid: inout [[Int]]) {
let rows = grid.count
let cols = grid[0].count
var visit: Set<[Int]> = []
func addRoom(_ r: Int, _ c: Int) {
if (r < 0 || r == rows || c < 0 || c == cols || visit.contains([r, c]) || grid[r][c] == -1) {
return
}
visit.insert([r, c])
q.append([r, c])
}
var q: [[Int]] = []
for r in 0 ..< rows {
for c in 0 ..< cols {
if grid[r][c] == 0 {
q.append([r, c])
visit.insert([r, c])
}
}
}
var dist = 0
while !q.isEmpty {
for _ in 0 ..< q.count {
let cell = q.removeFirst()
let r = cell[0]
let c = cell[1]
grid[r][c] = dist
addRoom(r + 1, c)
addRoom(r - 1, c)
addRoom(r, c + 1)
addRoom(r, c - 1)
}
dist += 1
}
}
Explanation
We can optimize our brute force solution by using the breadth first search algorithm. Let’s look at an example when we start from the second row and first column position:
- We are going to visit all four directions and find what is the closest gate that we can get to.
- To avoid a scenario where we visit the same position twice, we are going to create a
visited
set. We can’t achieve anO(m*n)
time solution if we are going to do breadth first search from the rooms, but if we do BFS from the gates, we can mark all adjacent rooms with distance1
. You can see if we start calculating distance from the gate with the position of the first row and third column, we have an incorrect distance for the bottom left gate. To avoid this scenario, we are going to simultaneously do a BFS from both gates. When we do our BFS from the bottom left gate, we are not going to visit the second column because it has already been visited.
Time/Space complexity
- Time complexity: O(m*n)
- Space complexity: O(m*n)
- Where
m
is the number of rows andn
is the number of columns in the grid