Given an m x n
binary matrix mat
, return the distance of the nearest 0
for each cell.
The distance between two cells sharing a common edge is 1
.
For example:
Input: mat = [[0,0,0],[0,1,0],[0,0,0]]
Output: [[0,0,0],[0,1,0],[0,0,0]]
Input: mat = [[0,0,0],[0,1,0],[1,1,1]]
Output: [[0,0,0],[0,1,0],[1,2,1]]
What is the most efficient way to accomplish this? What is the time and space complexity of your approach? Consider edge cases such as an empty matrix or a matrix with all 0s. Write the code for the most efficient approach.
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 looking at a grid of cells, some marked 'zero' and others marked 'one'. The brute force method finds, for each 'one' cell, how far away the nearest 'zero' cell is by checking every possibility. It explores outwards from each 'one' cell, step by step, until it finds a 'zero'.
Here's how the algorithm would work step-by-step:
def zero_one_matrix_brute_force(matrix):
number_rows = len(matrix)
number_columns = len(matrix[0])
result_matrix = [[0] * number_columns for _ in range(number_rows)]
for row in range(number_rows):
for column in range(number_columns):
if matrix[row][column] == 1:
distance = 0
found_zero = False
while not found_zero:
distance += 1
# Explore outwards, increasing the search radius
for row_offset in range(-distance, distance + 1):
column_offset = distance - abs(row_offset)
if 0 <= row + row_offset < number_rows and 0 <= column + column_offset < number_columns:
if matrix[row + row_offset][column + column_offset] == 0:
result_matrix[row][column] = distance
found_zero = True
break
column_offset = -column_offset
if 0 <= row + row_offset < number_rows and 0 <= column + column_offset < number_columns and column_offset != (distance - abs(row_offset)) * -1:
if matrix[row + row_offset][column + column_offset] == 0:
result_matrix[row][column] = distance
found_zero = True
break
if found_zero:
break
return result_matrix
The best way to solve this is to think about building outwards from the zeroes. Imagine the zeroes are like sources of water, and the numbers around them get 'wet' based on how far away they are from the water. We can efficiently find the distance to the nearest zero for every number in the grid.
Here's how the algorithm would work step-by-step:
def zero_one_matrix(matrix):
rows = len(matrix)
cols = len(matrix[0])
maximum_distance = rows + cols
# Initialize all non-zero elements to infinity
for row_index in range(rows):
for col_index in range(cols):
if matrix[row_index][col_index] != 0:
matrix[row_index][col_index] = maximum_distance
# Top to bottom, left to right
for row_index in range(rows):
for col_index in range(cols):
if matrix[row_index][col_index] != 0:
# Check top neighbor if within bounds
if row_index > 0:
matrix[row_index][col_index] = min(matrix[row_index][col_index], matrix[row_index-1][col_index] + 1)
# Check left neighbor if within bounds
if col_index > 0:
matrix[row_index][col_index] = min(matrix[row_index][col_index], matrix[row_index][col_index-1] + 1)
# Bottom to top, right to left
for row_index in range(rows-1, -1, -1):
for col_index in range(cols-1, -1, -1):
if matrix[row_index][col_index] != 0:
# Check bottom neighbor if within bounds
if row_index < rows - 1:
matrix[row_index][col_index] = min(matrix[row_index][col_index], matrix[row_index+1][col_index] + 1)
# Check right neighbor if within bounds
if col_index < cols - 1:
matrix[row_index][col_index] = min(matrix[row_index][col_index], matrix[row_index][col_index+1] + 1)
return matrix
Case | How to Handle |
---|---|
Null or empty input matrix | Return null or an empty matrix to indicate invalid input. |
Matrix with only one cell | Return a matrix with a single cell containing 0 if the cell is 0, or infinity (represented by a large number) if the cell is 1. |
Matrix with all 0s | The resulting matrix will be all 0s, handled correctly by BFS since initial queue will contain all cells. |
Matrix with all 1s | The resulting matrix will contain the distance to the nearest boundary, which can be handled by initializing the result with infinity (a large number) and updating during BFS. |
Very large matrix (memory constraints) | BFS approach works as it processes nodes level by level; however, large queue size might exhaust memory, so consider memory optimization techniques if available. |
Integer overflow when calculating distances in large matrices | Use a data type with sufficient range (e.g., long) to store the distances, or implement checks to prevent overflow. |
Matrix with a single 0 surrounded by 1s | The BFS algorithm will correctly propagate the distance from the single 0 to its surrounding 1s. |
Disconnected regions of 0s | The BFS algorithm will correctly calculate distances from each region of 0s independently. |