Loading problems...
TL;DR: The optimal solution utilizes Breadth-First Search (BFS) to traverse the grid layer-by-layer, guaranteeing that the first time the bottom-right cell is reached, the path taken is the shortest possible.
The Shortest Path in Binary Matrix problem asks us to find the length of the shortest path from the top-left cell (0, 0) to the bottom-right cell (n-1, n-1) in a square binary grid. We can only move through cells containing a 0, and movement is allowed in 8 directions (horizontal, vertical, and diagonal). The result should be the count of cells visited in the path. If no path exists, we return -1.
This is a classic interview question found in LeetCode 1091. It tests a candidate's ability to model a grid as a graph and choose the correct traversal algorithm for finding shortest paths in unweighted graphs.
The naive approach to solving this problem involves using Depth-First Search (DFS). In DFS, we explore a path as far as possible before backtracking. To find the shortest path, we would have to explore every valid path from start to finish and keep track of the minimum length found.
(0, 0).currentPathLength.(n-1, n-1), compare currentPathLength with the global minimum.textfunction dfs(row, col, count): if out_of_bounds OR cell_is_1 OR visited: return if row == n-1 AND col == n-1: min_path = min(min_path, count) return mark (row, col) as visited for each neighbor in 8 directions: dfs(neighbor_row, neighbor_col, count + 1) unmark (row, col) // Backtrack
The critical intuition for LeetCode 1091 is understanding how Breadth-First Search (BFS) explores a graph. Unlike DFS, which dives deep, BFS expands outwards in concentric layers.
k from the start before processing any node at distance k+1.(n-1, n-1), we are mathematically guaranteed that the current path length is the minimum possible. We do not need to continue searching.Visual Description:
Imagine dropping a stone into a pond at (0, 0). The ripples expand outward uniformly in all directions. The first ripple to touch the bottom-right corner represents the shortest path.
Technically, the algorithm maintains a queue. Initially, the queue contains the start node (Layer 0). We dequeue all nodes from Layer 0, identify their valid unvisited neighbors, and enqueue them as Layer 1. This process repeats. The state of the traversal moves from the top-left, filling the available 0 cells like a flood, until the target is reached.

Let's trace the execution for a simple grid: [[0,1],[1,0]].
grid[0][0]. It is 0. Valid.[(0, 0, 1)] (row, col, length). Mark (0, 0) as visited (set to 1).(0, 0, 1).(1, 1). Current is (0, 0). Not target.(0, 0).
(0, 1): Value is 1. Blocked. Ignore.(1, 0): Value is 1. Blocked. Ignore.(1, 1): Value is 0. Valid.
(1, 1) as visited.(1, 1, 2).(1, 1, 2).(1, 1). Current is (1, 1). Match found.2.The correctness of this BFS solution relies on the Monotonicity of Path Lengths.
cppclass Solution { public: int shortestPathBinaryMatrix(vector<vector<int>>& grid) { int n = grid.size(); // Edge case: Start or end is blocked if (grid[0][0] == 1 || grid[n-1][n-1] == 1) { return -1; } // Queue stores {row, col} queue<pair<int, int>> q; q.push({0, 0}); // Mark as visited by overwriting the grid to 1 grid[0][0] = 1; // 8-directional offsets int directions[8][2] = { {-1, -1}, {-1, 0}, {-1, 1}, {0, -1}, {0, 1}, {1, -1}, {1, 0}, {1, 1} }; int pathLength = 1; while (!q.empty()) { int levelSize = q.size(); // Process current level for (int i = 0; i < levelSize; i++) { auto [r, c] = q.front(); q.pop(); // Check if reached bottom-right if (r == n - 1 && c == n - 1) { return pathLength; } // Explore neighbors for (auto& dir : directions) { int nr = r + dir[0]; int nc = c + dir[1]; // Check bounds and if cell is 0 (clear/unvisited) if (nr >= 0 && nr < n && nc >= 0 && nc < n && grid[nr][nc] == 0) { q.push({nr, nc}); grid[nr][nc] = 1; // Mark visited immediately } } } pathLength++; } return -1; } };
javaclass Solution { public int shortestPathBinaryMatrix(int[][] grid) { int n = grid.length; // Edge case: Start or end is blocked if (grid[0][0] == 1 || grid[n-1][n-1] == 1) { return -1; } Queue<int[]> queue = new LinkedList<>(); queue.offer(new int[]{0, 0}); grid[0][0] = 1; // Mark visited int[][] directions = { {-1, -1}, {-1, 0}, {-1, 1}, {0, -1}, {0, 1}, {1, -1}, {1, 0}, {1, 1} }; int pathLength = 1; while (!queue.isEmpty()) { int size = queue.size(); for (int i = 0; i < size; i++) { int[] current = queue.poll(); int r = current[0]; int c = current[1]; if (r == n - 1 && c == n - 1) { return pathLength; } for (int[] dir : directions) { int nr = r + dir[0]; int nc = c + dir[1]; if (nr >= 0 && nr < n && nc >= 0 && nc < n && grid[nr][nc] == 0) { queue.offer(new int[]{nr, nc}); grid[nr][nc] = 1; // Mark visited immediately } } } pathLength++; } return -1; } }
pythonfrom collections import deque class Solution: def shortestPathBinaryMatrix(self, grid: List[List[int]]) -> int: n = len(grid) # Edge case: Start or end is blocked if grid[0][0] == 1 or grid[n-1][n-1] == 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, dist = queue.popleft() if r == n - 1 and c == n - 1: return dist for dr, dc in directions: nr, nc = r + dr, c + dc if 0 <= nr < n and 0 <= nc < n and grid[nr][nc] == 0: grid[nr][nc] = 1 # Mark visited immediately queue.append((nr, nc, dist + 1)) return -1
Let be the number of rows (and columns) in the grid. The total number of cells is .
Time Complexity: In the worst case (a grid full of zeros), we visit every cell exactly once. For each cell, we perform a constant number of operations (checking 8 neighbors). Thus, the time complexity is proportional to the total number of cells.
Space Complexity:
The Graph BFS pattern used here is highly versatile. It applies to several other popular interview questions:
In all these cases, the core logic remains: use a queue to process nodes level-by-level to determine minimum distance or time.
Why did my solution get Time Limit Exceeded (TLE)?
Why did I run out of memory (MLE) even with BFS?
Why is my answer wrong for simple cases?