from collections import deque
class Solution:
def shortestPathBinaryMatrix(self, grid):
n = len(grid)
if grid[0][0] != 0 or grid[n-1][n-1] != 0:
return -1
directions = [(-1, -1), (-1, 0), (-1, 1),
(0, -1), (0, 1),
(1, -1), (1, 0), (1, 1)]
queue = deque()
queue.append((0, 0, 1)) # (row, col, path_length)
visited = set((0, 0))
while queue:
r, c, length = queue.popleft()
if r == n - 1 and c == n - 1:
return length
for dr, dc in directions:
nr, nc = r + dr, c + dc
if (0 <= nr < n and 0 <= nc < n and
grid[nr][nc] == 0 and (nr, nc) not in visited):
visited.add((nr, nc))
queue.append((nr, nc, length + 1))
return -1
#include <vector>
#include <queue>
using namespace std;
class Solution {
public:
int shortestPathBinaryMatrix(vector<vector<int>>& grid) {
int n = grid.size();
if (grid[0][0] != 0 || grid[n-1][n-1] != 0) return -1;
vector<pair<int,int>> dirs = {{-1,-1},{-1,0},{-1,1},{0,-1},{0,1},{1,-1},{1,0},{1,1}};
queue<tuple<int,int,int>> q;
q.emplace(0, 0, 1);
vector<vector<bool>> visited(n, vector<bool>(n, false));
visited[0][0] = true;
while (!q.empty()) {
auto [r, c, len] = q.front(); q.pop();
if (r == n - 1 && c == n - 1) return len;
for (auto [dr, dc] : dirs) {
int nr = r + dr, nc = c + dc;
if (nr >= 0 && nr < n && nc >= 0 && nc < n &&
grid[nr][nc] == 0 && !visited[nr][nc]) {
visited[nr][nc] = true;
q.emplace(nr, nc, len + 1);
}
}
}
return -1;
}
};
import java.util.*;
class Solution {
public int shortestPathBinaryMatrix(int[][] grid) {
int n = grid.length;
if (grid[0][0] != 0 || grid[n-1][n-1] != 0) return -1;
int[][] directions = {{-1,-1},{-1,0},{-1,1},{0,-1},{0,1},{1,-1},{1,0},{1,1}};
Queue<int[]> queue = new LinkedList<>();
queue.offer(new int[]{0, 0, 1});
boolean[][] visited = new boolean[n][n];
visited[0][0] = true;
while (!queue.isEmpty()) {
int[] curr = queue.poll();
int r = curr[0], c = curr[1], len = curr[2];
if (r == n - 1 && c == n - 1) return len;
for (int[] d : directions) {
int nr = r + d[0], nc = c + d[1];
if (nr >= 0 && nr < n && nc >= 0 && nc < n
&& grid[nr][nc] == 0 && !visited[nr][nc]) {
visited[nr][nc] = true;
queue.offer(new int[]{nr, nc, len + 1});
}
}
}
return -1;
}
}
/**
* @param {number[][]} grid
* @return {number}
*/
var shortestPathBinaryMatrix = function(grid) {
const n = grid.length;
if (grid[0][0] !== 0 || grid[n-1][n-1] !== 0) return -1;
const directions = [
[-1,-1], [-1,0], [-1,1],
[0,-1], [0,1],
[1,-1], [1,0], [1,1]
];
const queue = [[0, 0, 1]];
const visited = Array.from({length: n}, () => Array(n).fill(false));
visited[0][0] = true;
while (queue.length) {
const [r, c, len] = queue.shift();
if (r === n - 1 && c === n - 1) return len;
for (const [dr, dc] of directions) {
const nr = r + dr, nc = c + dc;
if (
nr >= 0 && nr < n && nc >= 0 && nc < n &&
grid[nr][nc] === 0 && !visited[nr][nc]
) {
visited[nr][nc] = true;
queue.push([nr, nc, len + 1]);
}
}
}
return -1;
};
You are given an n x n
binary matrix called grid
. Your goal is to find the length of the shortest clear path from the top-left cell (grid[0][0]
) to the bottom-right cell (grid[n-1][n-1]
).
0
(not blocked).-1
.The input matrix is always square. The path length is defined as the number of cells visited, including the start and end cells.
Let's break down the requirements and think about how to approach the problem:
k
before moving to paths of length k+1
.
-1
.
The key insight is that BFS, combined with marking visited cells, will efficiently find the answer without redundant work.
Let's walk through the steps of the algorithm:
grid[0][0]
or grid[n-1][n-1]
is 1
(blocked), return -1
immediately.
-1
.
This approach guarantees that the first time we reach the end cell, it is via the shortest possible path.
Let's consider the following input:
grid = [ [0,1,0], [1,0,1], [0,0,0] ]
(0,0)
. It's clear, so we begin BFS with path length = 1
.
(0,0)
, the only valid move is to (1,1)
(diagonal down-right), since (0,1)
and (1,0)
are blocked.
(1,1)
with path length = 2
. From here, valid moves are (2,0)
and (2,1)
.
(2,0)
and (2,1)
to the queue with path length = 3
.
(2,0)
, the only valid unvisited neighbor is (2,1)
, but it's already in the queue.
(2,1)
, we can move to (2,2)
(the end cell).
(2,2)
at path length = 4
. Return 4
.
The shortest path is: (0,0) -> (1,1) -> (2,1) -> (2,2)
, which is 4 steps.
O(2^{n^2})
in the worst case, which is completely infeasible for even small grids.
O(n^2)
, because each cell is visited at most once, and we process up to 8 neighbors for each.
O(n^2)
, for the visited matrix and the queue in the worst case.
BFS is optimal for this problem because it explores all shortest paths first and avoids unnecessary exploration.
The "Shortest Path in Binary Matrix" problem is a classic application of BFS for grid-based pathfinding. The crucial insights are:
Mastering this approach is foundational for many grid and graph traversal problems in programming interviews.