01 Matrix

Medium BFS

Problem

Given a matrix mat consisting of 0s and 1s, return a matrix where each cell contains the distance to the nearest 0 in mat.

  • m == mat.length
  • n == mat[i].length
  • 1 ≤ m, n ≤ 10⁴
  • 1 ≤ m * n ≤ 10⁴
  • mat[i][j] is either 0 or 1
  • There is at least one 0 in mat

Example

Input: mat = [[0,0,0],[0,1,0],[1,1,1]]
Output: [[0,0,0],[0,1,0],[1,2,1]]

The algorithm starts by enqueuing all cells containing 0, treating them as sources. Each 1 cell is initialized to infinity to represent unknown distance. The BFS then expands outward from all zero cells simultaneously, updating the distance of neighboring cells if a shorter path is found. For example, the cell at (2,1) initially set to infinity is updated to 2 after exploring neighbors, reflecting the shortest path to the nearest zero at (1,1). This multi-source BFS ensures that each cell's distance is computed optimally by exploring the grid layer by layer.

Approach

Straightforward Solution

A brute-force approach would run a BFS or DFS from every cell containing 1 to find the nearest zero, resulting in O(m^2 * n^2) time complexity, which is infeasible for large matrices.

Core Observation

The shortest distance from any cell to the nearest zero can be found by exploring the grid in layers starting from all zero cells simultaneously. This is because the distance metric is uniform (each step costs 1), making BFS the natural choice for shortest path in an unweighted grid.

Path to Optimal

The key insight is to reverse the problem: instead of searching from each 1 to find the nearest 0, start from all 0s at once and propagate distances outward. This multi-source BFS ensures each cell is visited once with the shortest distance assigned, reducing complexity to O(m*n).

Optimal Approach

Initialize a queue with all zero cells and set all 1 cells to infinity. Perform BFS by dequeuing a cell, checking its neighbors, and updating their distances if a shorter path is found. Enqueue updated neighbors to continue propagation. Return the updated matrix after BFS completes.

Time

O(m * n)

Each cell is enqueued and processed at most once. The BFS explores all neighbors in constant time per cell, resulting in linear time relative to the number of cells.

Space

O(m * n)

The queue can hold up to all cells in the worst case, and the matrix is updated in place. This auxiliary space is necessary to track the BFS frontier.

Pattern Spotlight

BFS (Multi-Source Traversal)

When shortest distances to multiple sources are needed, enqueue all sources initially and perform BFS simultaneously to propagate minimum distances efficiently.

Solution

1class Solution:
2 def updateMatrix(self, mat: List[List[int]]) -> List[List[int]]:
3 rows, cols = len(mat), len(mat[0])
4 q = deque()
5
6 for r in range(rows):
7 for c in range(cols):
8 if mat[r][c] == 0:
9 q.append((r, c))
10 else:
11 mat[r][c] = float('inf')
12
13 directions = [(1,0), (-1,0), (0,1), (0,-1)]
14
15 while q:
16 r, c = q.popleft()
17
18 for dr, dc in directions:
19 nr, nc = r + dr, c + dc
20
21 if 0 <= nr < rows and 0 <= nc < cols and mat[nr][nc] > mat[r][c] + 1:
22 mat[nr][nc] = mat[r][c] + 1
23 q.append((nr, nc))
24
25 return mat

Step-by-Step Solution

1

Initialize Queue with Zero Cells and Mark Ones as Infinite Distance

3rows, cols = len(mat), len(mat[0])
4q = deque()
6for r in range(rows):
7 for c in range(cols):
8 if mat[r][c] == 0:
9 q.append((r, c))
10 else:
11 mat[r][c] = float('inf')

Objective

To prepare the BFS by enqueuing all zero cells as starting points and marking all one cells with infinite distance to indicate they are unvisited.

Key Insight

By treating all zero cells as simultaneous sources, the BFS can propagate distances outward efficiently. Marking one cells as infinity ensures that any update to a smaller distance is meaningful and prevents revisiting cells unnecessarily.

Interview Quick-Check

Core Logic

Enqueuing all zero cells at the start enables multi-source BFS, which finds shortest distances to zeros in a single pass.

State & Boundaries

Marking one cells as infinity distinguishes unvisited cells and allows the BFS to update distances only when a shorter path is found.

Common Pitfalls & Bugs

Failing to initialize one cells to infinity can cause incorrect distance updates or infinite loops.

2

Perform BFS to Update Distances by Exploring Neighbors

13directions = [(1,0), (-1,0), (0,1), (0,-1)]
15while q:
16 r, c = q.popleft()
18 for dr, dc in directions:
19 nr, nc = r + dr, c + dc
21 if 0 <= nr < rows and 0 <= nc < cols and mat[nr][nc] > mat[r][c] + 1:
22 mat[nr][nc] = mat[r][c] + 1
23 q.append((nr, nc))

Objective

To iteratively explore neighbors of each dequeued cell, updating their distances if a shorter path is found, and enqueueing them for further exploration.

Key Insight

The BFS ensures that when a neighbor's distance is updated, it is the shortest possible distance from any zero. By only updating when a strictly shorter distance is found, the algorithm avoids redundant work and guarantees correctness.

Interview Quick-Check

Core Logic

The BFS loop dequeues cells and updates neighbors' distances if the new distance is smaller, ensuring shortest paths propagate outward.

State & Boundaries

The boundary checks ensure neighbors are within matrix bounds before processing.

Common Pitfalls & Bugs

Not checking if the neighbor's current distance is greater than the new distance can cause incorrect updates and infinite loops.

Complexity

Each cell is enqueued at most once after its distance is updated, ensuring O(m*n) time complexity.

3

Return the Matrix with Updated Distances

25return mat

Objective

To return the matrix after BFS completes, where each cell contains the shortest distance to the nearest zero.

Key Insight

After BFS finishes, all cells have been assigned the minimum distance to a zero, as BFS guarantees shortest path discovery in unweighted graphs.

Interview Quick-Check

Core Logic

Returning the updated matrix completes the solution, providing the required output.

Line Analysis

This solution has 6 Critical lines interviewers watch for.

Line 21 Critical
if 0 <= nr < rows and 0 <= nc < cols and mat[nr][nc] > mat[r][c] + 1:

Check if neighbor is within bounds and if its current distance is greater than the new possible distance.

This compound condition ensures only valid neighbors are processed and that distances are updated only when a shorter path is found, preventing redundant work and infinite loops.

Line 8 Critical
if mat[r][c] == 0:

Check if the current cell contains zero.

Identifying zero cells is critical because they serve as BFS starting points for distance propagation.

Line 9 Critical
q.append((r, c))

Add zero cells to the BFS queue as starting points.

Enqueuing all zero cells initially enables multi-source BFS, which efficiently computes shortest distances to zeros.

Line 11 Critical
mat[r][c] = float('inf')

Set the distance of one cells to infinity.

Assigning infinity marks these cells as unvisited and ensures that any discovered shorter distance will update them correctly during BFS.

Line 16 Critical
r, c = q.popleft()

Dequeue the next cell to process.

Dequeuing maintains BFS's FIFO order, which is essential for guaranteeing shortest path discovery.

Line 22 Critical
mat[nr][nc] = mat[r][c] + 1

Update the neighbor's distance to the shorter path found.

Assigning the new distance reflects the shortest path discovered so far and enables correct BFS propagation.

Line 4 Core
q = deque()

Initialize a queue to hold cells for BFS traversal.

The queue is essential for BFS, enabling layer-by-layer exploration starting from all zero cells.

Line 15 Core
while q:

Continue BFS while there are cells in the queue.

The loop processes cells layer by layer, ensuring distances are propagated in order of increasing distance from zero cells.

Line 23 Core
q.append((nr, nc))

Enqueue the neighbor for further BFS exploration.

Adding the neighbor to the queue ensures its neighbors will be explored in subsequent BFS layers, continuing the distance propagation.

Line 10 Core
else:

Handle cells that contain one.

Cells with value one are not sources and need their distances initialized to infinity to indicate they are unvisited.

Line 13 Core
directions = [(1,0), (-1,0), (0,1), (0,-1)]

Define the four possible directions for neighbor exploration (up, down, left, right).

These direction vectors enable systematic neighbor traversal in the grid, which is fundamental to BFS expansion.

Line 18 Core
for dr, dc in directions:

Iterate over all four neighbor directions.

Exploring neighbors is necessary to propagate distance updates to adjacent cells.

Line 25 Core
return mat

Return the matrix with updated distances.

After BFS completes, the matrix contains the shortest distances to the nearest zero for every cell, fulfilling the problem requirements.

Line 19 Standard
nr, nc = r + dr, c + dc

Calculate the neighbor's row and column indices.

Computing neighbor coordinates allows boundary checks and distance updates for valid neighbors.

Line 6 Standard
for r in range(rows):

Iterate over each row index.

This nested loop structure systematically visits every cell in the matrix to initialize BFS sources and distances.

Line 7 Standard
for c in range(cols):

Iterate over each column index within the current row.

Completes the traversal of the entire matrix grid cell by cell.

Line 3 Basic
rows, cols = len(mat), len(mat[0])

Calculate the number of rows and columns in the matrix.

Caching the dimensions avoids repeated calls to len() and simplifies boundary checks throughout the algorithm.

Test Your Understanding

Why does starting BFS from all zero cells simultaneously guarantee the shortest distance to the nearest zero for every cell?

Because BFS explores nodes in order of increasing distance from the sources, the first time a cell is reached is via the shortest path from any zero. Starting from all zeros ensures all shortest paths are found in a single traversal.

Related Problems

BFS pattern

Don't just read it. Drill it.

Reconstruct 01 Matrix from memory until it sticks. AlgoDrill blanks out key lines and makes you fill them back in, step by step.

Unlock the 01 Matrix drill

or drill a free problem