Given a binary grid[][] where each cell contains either 0 or 1, find for every cell the minimum Manhattan distance to the nearest cell having value 1. The Manhattan distance between (i1, j1) and (i2, j2) is |i1 - i2| + |j1 - j2|. You must return a matrix of the same size where each cell contains that minimum distance. It's guaranteed there is at least one 1 in the grid.
1 ≤ grid.size() ≤ 200(rows)1 ≤ grid[0].size() ≤ 200(columns)- Each
grid[i][j]is either0or1.
I thought about finding the nearest 1 for each 0. Running a BFS from every 0 independently would repeat a lot of work. So I reversed the idea: start BFS from all 1 cells at once (multi-source BFS). As BFS expands level-by-level from all 1s, the first time a 0 cell is reached gives its shortest distance to any 1. This way each cell is visited once and distances are computed in optimal time.
- Create a
distmatrix same size asgrid. Initialize distances for1cells to0and others to-1(unknown). - Push all coordinates of cells that contain
1into a queue (these are the BFS sources). - Perform BFS: pop a cell, check its 4 neighbors (up, down, left, right). If neighbor is unvisited (
dist == -1), setdist[neighbor] = dist[current] + 1and push neighbor. - Continue until the queue is empty.
distnow holds minimal Manhattan distances to nearest1.
This is a multi-source BFS pattern on a grid with uniform edge weights (1).
- 2D Array / Vector for
dist. - Queue (FIFO) for BFS.
- Optional visited boolean grid (or reuse
dist == -1to indicate unvisited).
- Initialization: O(m * n) to prepare
distand enqueue all1s. - BFS: each cell is enqueued/processed at most once; each cell checks up to 4 neighbors.
- Final
distcontains shortest Manhattan distances to a nearest1.
- Time Complexity:
O(m * n)— wherem= rows andn= columns. Each cell is visited once and we consider at most 4 neighbors for each visit. - Space Complexity:
O(m * n)— for thedistarray and worst-case BFS queue size.
#include <bits/stdc++.h>
using namespace std;
class Solution {
public:
vector<vector<int>> nearest(vector<vector<int>>& grid) {
int m = grid.size();
if (m == 0) return {};
int n = grid[0].size();
vector<vector<int>> dist(m, vector<int>(n, -1));
queue<pair<int,int>> q;
// enqueue all 1-cells with distance 0
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
if (grid[i][j] == 1) {
dist[i][j] = 0;
q.push({i, j});
}
}
}
// 4-directional moves
int dr[4] = {-1, 1, 0, 0};
int dc[4] = {0, 0, -1, 1};
// multi-source BFS
while (!q.empty()) {
auto [r, c] = q.front(); q.pop();
for (int k = 0; k < 4; ++k) {
int nr = r + dr[k], nc = c + dc[k];
if (nr >= 0 && nr < m && nc >= 0 && nc < n && dist[nr][nc] == -1) {
dist[nr][nc] = dist[r][c] + 1;
q.push({nr, nc});
}
}
}
return dist;
}
};import java.util.*;
class Solution {
public ArrayList<ArrayList<Integer>> nearest(int[][] grid) {
int m = grid.length;
if (m == 0) return new ArrayList<>();
int n = grid[0].length;
int[][] dist = new int[m][n];
boolean[][] vis = new boolean[m][n];
for (int i = 0; i < m; i++) Arrays.fill(dist[i], -1);
Queue<int[]> q = new LinkedList<>();
// initialize queue with all 1's
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (grid[i][j] == 1) {
dist[i][j] = 0;
vis[i][j] = true;
q.offer(new int[]{i, j});
}
}
}
int[] dr = {-1, 1, 0, 0};
int[] dc = {0, 0, -1, 1};
while (!q.isEmpty()) {
int[] cur = q.poll();
int r = cur[0], c = cur[1];
for (int k = 0; k < 4; k++) {
int nr = r + dr[k], nc = c + dc[k];
if (nr >= 0 && nr < m && nc >= 0 && nc < n && !vis[nr][nc]) {
vis[nr][nc] = true;
dist[nr][nc] = dist[r][c] + 1;
q.offer(new int[]{nr, nc});
}
}
}
ArrayList<ArrayList<Integer>> result = new ArrayList<>();
for (int i = 0; i < m; i++) {
ArrayList<Integer> row = new ArrayList<>();
for (int j = 0; j < n; j++) row.add(dist[i][j]);
result.add(row);
}
return result;
}
}/**
* @param {number[][]} grid
* @returns {number[][]}
*/
class Solution {
nearest(grid) {
const m = grid.length;
if (m === 0) return [];
const n = grid[0].length;
const dist = Array.from({length: m}, () => Array(n).fill(-1));
const q = [];
let head = 0;
// enqueue all 1-cells
for (let i = 0; i < m; ++i) {
for (let j = 0; j < n; ++j) {
if (grid[i][j] === 1) {
dist[i][j] = 0;
q.push([i, j]);
}
}
}
const dirs = [[-1,0],[1,0],[0,-1],[0,1]];
while (head < q.length) {
const [r, c] = q[head++];
for (const [dr, dc] of dirs) {
const nr = r + dr, nc = c + dc;
if (nr >= 0 && nr < m && nc >= 0 && nc < n && dist[nr][nc] === -1) {
dist[nr][nc] = dist[r][c] + 1;
q.push([nr, nc]);
}
}
}
return dist;
}
}from collections import deque
class Solution:
def nearest(self, grid):
m = len(grid)
if m == 0:
return []
n = len(grid[0])
dist = [[-1] * n for _ in range(m)]
q = deque()
# initialize queue with all 1's
for i in range(m):
for j in range(n):
if grid[i][j] == 1:
dist[i][j] = 0
q.append((i, j))
dirs = [(-1,0), (1,0), (0,-1), (0,1)]
while q:
r, c = q.popleft()
for dr, dc in dirs:
nr, nc = r + dr, c + dc
if 0 <= nr < m and 0 <= nc < n and dist[nr][nc] == -1:
dist[nr][nc] = dist[r][c] + 1
q.append((nr, nc))
return distI'll explain key blocks that are common across implementations. The code is essentially the same algorithm implemented in different languages.
-
Initialize
distand queue of sources-
I create an output matrix
distwith the same dimensions asgrid. -
For each cell:
- If
grid[i][j] == 1, setdist[i][j] = 0and push(i, j)into the BFS queue. - If
grid[i][j] == 0, setdist[i][j] = -1(means the cell is not visited yet).
- If
Reason: All
1cells are distance 0 to themselves and will be the starting points for BFS. -
-
Define neighbor moves
- Use 4-directional move vectors: up, down, left, right.
- These represent one-step Manhattan moves.
-
Multi-source BFS loop
-
While the queue is not empty:
-
Pop current cell
(r, c). -
For each neighbor
(nr, nc):-
If neighbor is in bounds and not visited (
dist[nr][nc] == -1):- Set
dist[nr][nc] = dist[r][c] + 1. - Push
(nr, nc)into queue.
- Set
-
-
-
Because BFS expands in layers, the first time we set
dist[nr][nc]is the shortest path from the nearest1.
-
-
Return
dist- Once BFS completes,
distcontains the desired minimum distances for all cells.
- Once BFS completes,
Input:
grid = [
[0, 1, 1, 0],
[1, 1, 0, 0],
[0, 0, 1, 1]
]
Output:
[
[1, 0, 0, 1],
[0, 0, 1, 1],
[1, 1, 0, 0]
]
Input:
grid = [
[1, 0, 1],
[1, 1, 0],
[1, 0, 0]
]
Output:
[
[0, 1, 0],
[0, 0, 1],
[0, 1, 2]
]
- Put the
nearestfunction in a drivermain()where you buildgridand call it. - Compile:
g++ -std=c++17 -O2 solution.cpp -o solution
./solution- Place
Solutionclass inSolution.java, and add amainmethod to instantiateSolutionand testnearest. - Compile & run:
javac Solution.java
java Solution- Save the class and driver/test code in
solution.js. - Run:
node solution.js- Save code in
solution.py, add a test harness to callSolution().nearest(grid). - Run:
python3 solution.py- Using
dist == -1as "not visited" avoids an extravisitedarray (saves memory). - The BFS queue can hold up to
O(m*n)items in worst case. This is expected and accounted in space complexity. - This algorithm is optimal for this problem: BFS with multiple sources gives the shortest distances in
O(m*n). - For very large grids where memory is constrained, consider streaming or block processing patterns (but those are complex and rarely needed within given constraints).
- If diagonal moves were allowed (not in this problem), neighbor list would be extended and the metric would be Chebyshev or different — but here we use Manhattan distance and 4-neighbors.