You are given an m x n
grid representing a building with walls, gates, and empty rooms. Each cell in the grid can have one of three values:
-1
: Represents a wall.0
: Represents a gate.INF
: Represents an empty room. INF
is represented by the maximum integer value, 2147483647.Your task is to fill each empty room with the distance to its nearest gate. The distance is defined as the number of steps it takes to reach a gate. If an empty room cannot reach any gate, it should remain as INF
.
Example:
Consider the following grid:
INF -1 0 INF
INF INF INF -1
INF -1 INF -1
0 -1 INF INF
After running your algorithm, the grid should be modified to:
3 -1 0 1
2 2 1 -1
1 -1 2 -1
0 -1 3 4
Clarifications:
m
and n
are between 1 and 250.Describe an algorithm to solve this problem efficiently and provide the time and space complexity analysis. Also, consider any edge cases that might arise.
When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
Imagine you're exploring a building with rooms and want to find the shortest path from each room to the nearest exit. The brute force way involves walking from each room to every other room until you find an exit. You then repeat this process for all of the other rooms.
Here's how the algorithm would work step-by-step:
def walls_and_gates_brute_force(rooms):
rows = len(rooms)
cols = len(rooms[0]) if rows > 0 else 0
def find_shortest_path(start_row, start_col):
shortest_distance = float('inf')
def explore(current_row, current_col, distance, visited):
nonlocal shortest_distance
# Prevent infinite loops by marking as visited
if (current_row, current_col) in visited:
return
if not (0 <= current_row < rows and 0 <= current_col < cols):
return
if rooms[current_row][current_col] == -1:
return
# We found a gate
if rooms[current_row][current_col] == 0:
shortest_distance = min(shortest_distance, distance)
return
visited.add((current_row, current_col))
explore(current_row + 1, current_col, distance + 1, visited.copy())
explore(current_row - 1, current_col, distance + 1, visited.copy())
explore(current_row, current_col + 1, distance + 1, visited.copy())
explore(current_row, current_col - 1, distance + 1, visited.copy())
explore(start_row, start_col, 0, set())
return shortest_distance
for row_index in range(rows):
for col_index in range(cols):
# Only process rooms that are not walls or gates
if rooms[row_index][col_index] == 2147483647:
rooms[row_index][col_index] = find_shortest_path(row_index, col_index)
The problem is to fill in the empty rooms with the shortest distance to a gate. We can efficiently do this by starting at the gates and spreading outwards, layer by layer, updating each empty room's distance as we go. This ensures we find the shortest paths without re-calculating.
Here's how the algorithm would work step-by-step:
def walls_and_gates(rooms):
if not rooms:
return
rows_count = len(rooms)
columns_count = len(rooms[0])
queue = []
# Find all gates and add them to the queue for BFS
for row_index in range(rows_count):
for column_index in range(columns_count):
if rooms[row_index][column_index] == 0:
queue.append((row_index, column_index))
def add_room_to_queue(row_index, column_index, distance):
if 0 <= row_index < rows_count and 0 <= column_index < columns_count and \
rooms[row_index][column_index] == 2147483647:
rooms[row_index][column_index] = distance
queue.append((row_index, column_index))
# BFS to find the shortest distance to each room
distance = 1
while queue:
next_queue = []
for _ in range(len(queue)):
row_index, column_index = queue.pop(0)
# Check the neighbors of the current room
add_room_to_queue(row_index + 1, column_index, distance)
add_room_to_queue(row_index - 1, column_index, distance)
add_room_to_queue(row_index, column_index + 1, distance)
add_room_to_queue(row_index, column_index - 1, distance)
distance += 1
Case | How to Handle |
---|---|
Null or empty rooms array | Return immediately without processing, as there are no rooms to update. |
Rooms array with zero rows or zero columns | Return immediately, handling it as an invalid input scenario. |
All rooms are walls (-1) | The algorithm should terminate without modifying the grid, as there are no gates to start from. |
All rooms are gates (0) | The algorithm will iterate through the grid and all adjacent rooms will be updated to 1. |
All rooms are empty (INF = 2147483647) | The algorithm will correctly update all rooms with the distance to the nearest gate. |
Grid with only one cell which is a gate | The cell will remain 0 and the algorithm terminates. |
Grid with only one cell which is a wall | The cell will remain -1 and the algorithm terminates. |
Integer overflow when calculating distances from gates | The problem statement specifies INF as 2147483647, and using BFS ensures distances won't exceed this value since we are increasing by 1 at each step. |