AlgoMaster Logo

01 Matrix

mediumFrequency9 min readUpdated June 23, 2026

Understanding the Problem

We have a grid of 0s and 1s, and we need to compute a new grid where each cell contains the shortest Manhattan distance to the nearest 0. Cells that are already 0 get distance 0. Cells that are 1 need to find how far away the closest 0 is, counting only horizontal and vertical moves (not diagonal).

The direction of the search determines the cost. Searching outward from each 1-cell for the nearest 0 repeats the same work for every cell. Reversing the direction, starting from all the 0-cells and expanding outward at once, computes every answer in a single sweep: the first time the expansion reaches a 1-cell, that distance is its answer. Both efficient solutions below build on this reversal.

Key Constraints:

  • 1 <= m, n <= 10^4 and 1 <= m * n <= 10^4: the total number of cells is at most 10,000. A brute force BFS from every cell costs O((m*n)^2), about 10^8 operations, which is borderline.
  • mat[i][j] is either 0 or 1: every move between adjacent cells costs 1, so plain BFS finds shortest distances without a priority queue.
  • There is at least one 0 in mat: every cell has a finite answer, so there is no unreachable case to handle.

Approach 1: BFS from Each Cell (Brute Force)

Intuition

For every cell that contains a 1, start a BFS and expand outward until it reaches a 0. The number of levels traversed is the distance. Cells that are already 0 get distance 0 immediately.

This works because BFS explores cells layer by layer, so the first 0 encountered is the nearest one. The cost comes from running a separate BFS for every 1-cell, where each BFS can visit the entire grid in the worst case.

Algorithm

  1. Create a result matrix of the same dimensions as mat.
  2. For each cell (i, j) in the matrix:
    • If mat[i][j] == 0, set result[i][j] = 0.
    • Otherwise, run a BFS starting from (i, j). Explore all four neighbors level by level until a cell with value 0 is found. The number of levels traversed is the distance.
  3. Return the result matrix.

Example Walkthrough

With mat = [[0,0,0],[0,1,0],[1,1,1]], the five 0-cells get distance 0 directly. Each of the four 1-cells gets its own BFS:

The BFS runs for the three bottom-row cells re-scan overlapping neighborhoods of the grid, and none of them reuses anything the others computed.

Code

Every 1-cell launches an independent BFS, and these runs repeat the same scans over the same regions. The next approach removes the duplication by running one BFS in the opposite direction, from all 0-cells outward at once.

Approach 2: Multi-source BFS (Optimal)

Intuition

Instead of running a separate BFS from each 1-cell, run a single BFS starting from all 0-cells simultaneously. Add every 0-cell to the queue at the start with distance 0, then expand outward layer by layer. Because BFS explores in order of increasing distance, the first time the expansion reaches a 1-cell, the recorded distance is its answer.

An analogy: drop a stone into water at every 0-cell at the same moment. The ripples spread outward, and each cell is claimed by whichever ripple arrives first, which is always the one from the nearest source.

Algorithm

  1. Create a result matrix initialized to -1 (unvisited).
  2. Add all cells where mat[i][j] == 0 to the queue and set their distance to 0 in the result matrix.
  3. Process the queue using standard BFS. For each cell dequeued, check all four neighbors.
  4. If a neighbor has not been visited yet (distance is -1), set its distance to the current cell's distance + 1 and add it to the queue.
  5. Return the result matrix once the queue is empty.

Example Walkthrough

1Initialize: all 0-cells enqueued with dist=0, 1-cells marked as -1 (unvisited)
0
1
2
0
0
0
0
1
0
-1
0
2
-1
-1
-1
1/5

Code

Multi-source BFS is optimal in time but allocates a queue that can hold a large fraction of the grid. The final approach keeps the O(m * n) time and replaces the queue with two plain sweeps over the matrix.

Approach 3: Dynamic Programming (Two-Pass)

Intuition

The distance from any cell to the nearest 0 is determined by its neighbors. If a cell is not itself 0, its distance is 1 plus the minimum distance among its four neighbors. The challenge is that we cannot compute all four directions in a single pass because some neighbors have not been computed yet.

Splitting the computation into two passes resolves this. The first pass (top-left to bottom-right) considers the top and left neighbors. The second pass (bottom-right to top-left) considers the bottom and right neighbors. After both passes, every cell has accounted for all four directions.

Algorithm

  1. Create a distance matrix. Set dist[i][j] = 0 for 0-cells and dist[i][j] = m + n (a safe upper bound) for 1-cells.
  2. First pass (top-left to bottom-right): for each cell (i, j) in row-major order, if i > 0, set dist[i][j] = min(dist[i][j], dist[i-1][j] + 1). If j > 0, set dist[i][j] = min(dist[i][j], dist[i][j-1] + 1).
  3. Second pass (bottom-right to top-left): for each cell (i, j) in reverse row-major order, if i < m-1, set dist[i][j] = min(dist[i][j], dist[i+1][j] + 1). If j < n-1, set dist[i][j] = min(dist[i][j], dist[i][j+1] + 1).
  4. Return the distance matrix.

Example Walkthrough

1Initialize: 0-cells get 0, 1-cells get large value L=6 (m+n)
0
1
2
0
0
0
0
1
0
6
0
2
6
6
6
1/6

Code

If mutating the input is acceptable, the same two passes can run directly on mat itself, which removes even the output allocation. The forward-backward sweep also appears outside this problem: image processing calls it a two-pass distance transform (the Chamfer algorithm) and uses it to compute a distance field over an entire image without a queue.