You are given an m x n
grid rooms
initialized with these three possible values.
INF
which represents an empty room (represented as 2147483647
)-1
represents a wall0
represents a gate.You are to fill each empty room with the distance to its nearest gate. If it is impossible to reach a gate, that room should remain INF
.
For example, given the following input:
[ [INF, -1, 0, INF],
[INF, INF, INF, -1],
[INF, -1, INF, -1],
[0, -1, INF, INF]
]
Your function should modify the input rooms
array in-place to look like this:
[ [3, -1, 0, 1],
[2, 2, 1, -1],
[1, -1, 2, -1],
[0, -1, 3, 4]
]
Explain your approach, analyze its time and space complexity, and handle any potential edge cases. Provide the code for your solution. The goal is to find the most efficient way to solve this problem.
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. |