1091 - Shortest Path in Binary Matrix
Difficulty: Medium | Pattern: BFS on Grid | Company tags: Amazon, Facebook, Uber, Bloomberg
Problem Statement
Given an n x n binary matrix grid, return the length of the shortest clear path in the matrix. If there is no clear path, return -1.
A clear path in a binary matrix is a path from the top-left cell (0,0) to the bottom-right cell (n-1,n-1) such that:
- All visited cells of the path are
0. - All adjacent cells of the path are 8-directionally connected (can move diagonally).
The length of a clear path is the number of visited cells.
Example 1:
Input: [[0,1],[1,0]]
Output: 2 (path: (0,0) → (1,1))
Example 2:
Input: [[0,0,0],[1,1,0],[1,1,0]]
Output: 4
Approach: BFS — O(n²)
Key insight: BFS gives the shortest path in an unweighted graph. Start at (0,0), explore all 8 directions. Track visited by setting cells to 1.
Algorithm Flow
from collections import deque
def shortestPathBinaryMatrix(grid: list[list[int]]) -> int:
n = len(grid)
if grid[0][0] == 1 or grid[n-1][n-1] == 1:
return -1
if n == 1:
return 1
queue = deque([(0, 0, 1)]) # (row, col, path_length)
grid[0][0] = 1 # mark visited
directions = [(-1,-1),(-1,0),(-1,1),(0,-1),(0,1),(1,-1),(1,0),(1,1)]
while queue:
r, c, length = queue.popleft()
for dr, dc in directions:
nr, nc = r + dr, c + dc
if 0 <= nr < n and 0 <= nc < n and grid[nr][nc] == 0:
if nr == n-1 and nc == n-1:
return length + 1
grid[nr][nc] = 1 # mark visited
queue.append((nr, nc, length + 1))
return -1
Dry Run
grid = [[0,0,0],[1,1,0],[1,1,0]] (3×3)
BFS from (0,0):
- Length 1: (0,0) start
- Explore from (0,0): (0,1)=0 → queue; (1,1)=1 skip; (1,0)=1 skip...
- Length 2: (0,1)
- Explore from (0,1): (0,2)=0 → queue; (1,2)=0 → queue
- Length 3: (0,2), (1,2)
- From (1,2): (2,2) = bottom-right → return 3+1 = 4 ✓
Edge Cases
grid[0][0] = 1orgrid[n-1][n-1] = 1→ return -1 immediatelyn = 1andgrid[0][0] = 0→ return 1 (already at destination)- No path → return -1
Complexity
- Time: O(n²) — each cell visited at most once
- Space: O(n²) — BFS queue
Note: BFS is required here (not DFS) because we need the shortest path, not just any path.
Key Terms
| Term | Definition |
|---|---|
| BFS | Breadth-first search — explores nodes level by level, guaranteeing shortest path in unweighted graphs. |
| 8-directional adjacency | Neighbors include the 4 orthogonal and 4 diagonal cells around a point. |
| In-place visited marking | Reusing the grid itself (setting cleared cells to 1) instead of a separate visited set, saving space. |
| Level/path length | The BFS queue tracks the number of cells visited so far, which equals the path length by construction. |
| Early termination | Returning as soon as the destination cell is reached avoids exploring the rest of the queue unnecessarily. |
FAQ
Q: Can this be solved without extra space? A: Not entirely — even with in-place visited marking (mutating the input grid), the BFS queue itself requires O(n²) space in the worst case for a fully open grid.
Q: What if the grid is empty or 1x1?
A: An empty grid isn't a valid input per constraints, but the n == 1 case is handled explicitly — if grid[0][0] == 0, the answer is 1 (already at destination).
Q: How would this change if only 4-directional movement were allowed?
A: Just shrink the directions list to the 4 orthogonal moves; the BFS structure and shortest-path guarantee stay identical.
Q: What is the time complexity trade-off vs DFS? A: DFS can find a path in O(n²) but does not guarantee the shortest one without exploring all paths (exponential blowup); BFS guarantees shortest path in the same O(n²) by exploring level-by-level.
Q: Why mark a neighbor visited when enqueuing rather than when dequeuing? A: Marking at enqueue time prevents the same cell from being added to the queue multiple times by different in-progress paths, avoiding redundant work and duplicate expansion.
Quick Revision
- Goal: shortest 8-directionally-connected path of 0-cells from (0,0) to (n-1,n-1).
- Immediately return -1 if start or end cell is blocked (value 1).
- Special-case n == 1: answer is 1 if the single cell is open.
- Use BFS (not DFS) because BFS guarantees shortest path in unweighted graphs.
- Queue holds
(row, col, path_length); start with length 1 for the origin cell. - Explore all 8 directions per cell; mark visited immediately by setting grid value to 1.
- Return
length + 1the moment the destination cell is reached. - If the queue empties without reaching the destination, return -1.
- Time: O(n²), Space: O(n²) for the queue in the worst case.
Related Problems
- 200 - Number of Islands — same grid-BFS/DFS traversal pattern with 4-directional neighbors
- 695 - Max Area of Island — grid traversal counting connected component size
- 417 - Pacific Atlantic Water Flow — multi-source BFS/DFS on a grid