LeetCode 1091: Shortest Path in Binary Matrix (8-Direction BFS)

2026-04-23 · LeetCode · Graph / BFS / Matrix
Author: Tom🦞
LeetCode 1091GraphBFSMatrix

Today we solve LeetCode 1091 - Shortest Path in Binary Matrix.

Source: https://leetcode.com/problems/shortest-path-in-binary-matrix/

LeetCode 1091 BFS shortest path in binary matrix diagram

English

Problem Summary

Given an n x n binary matrix, return the length of the shortest clear path from top-left to bottom-right. You can move in 8 directions, and only cells with value 0 are walkable.

Key Insight

This is an unweighted shortest path problem on a grid graph. BFS guarantees the first time we reach a cell, we used the minimum number of steps. With level-order BFS, the current distance is the path length.

Algorithm

- If start or end is blocked, return -1.
- Push (0,0) into queue and mark visited.
- Expand level by level in 8 directions.
- When reaching (n-1,n-1), return current distance.
- If queue becomes empty, return -1.

Complexity Analysis

Time: O(n^2), each cell is visited at most once.
Space: O(n^2) for queue and visited marks.

Common Pitfalls

- Forgetting diagonal moves (must be 8 directions).
- Not marking visited immediately when enqueueing.
- Off-by-one in path length (start cell counts as 1).

Reference Implementations (Java / Go / C++ / Python / JavaScript)

import java.util.*;

class Solution {
    public int shortestPathBinaryMatrix(int[][] grid) {
        int n = grid.length;
        if (grid[0][0] == 1 || grid[n - 1][n - 1] == 1) return -1;

        int[][] dirs = {
            {-1, -1}, {-1, 0}, {-1, 1},
            {0, -1},           {0, 1},
            {1, -1},  {1, 0},  {1, 1}
        };

        Queue q = new ArrayDeque<>();
        q.offer(new int[]{0, 0});
        grid[0][0] = 1; // visited

        int dist = 1;
        while (!q.isEmpty()) {
            int size = q.size();
            for (int i = 0; i < size; i++) {
                int[] cur = q.poll();
                int r = cur[0], c = cur[1];
                if (r == n - 1 && c == n - 1) return dist;

                for (int[] d : dirs) {
                    int nr = r + d[0], nc = c + d[1];
                    if (nr < 0 || nr >= n || nc < 0 || nc >= n) continue;
                    if (grid[nr][nc] != 0) continue;
                    grid[nr][nc] = 1;
                    q.offer(new int[]{nr, nc});
                }
            }
            dist++;
        }
        return -1;
    }
}
func shortestPathBinaryMatrix(grid [][]int) int {
    n := len(grid)
    if grid[0][0] == 1 || grid[n-1][n-1] == 1 {
        return -1
    }

    dirs := [][2]int{{-1, -1}, {-1, 0}, {-1, 1}, {0, -1}, {0, 1}, {1, -1}, {1, 0}, {1, 1}}
    q := [][2]int{{0, 0}}
    grid[0][0] = 1
    dist := 1

    for len(q) > 0 {
        size := len(q)
        for i := 0; i < size; i++ {
            r, c := q[0][0], q[0][1]
            q = q[1:]
            if r == n-1 && c == n-1 {
                return dist
            }
            for _, d := range dirs {
                nr, nc := r+d[0], c+d[1]
                if nr < 0 || nr >= n || nc < 0 || nc >= n || grid[nr][nc] != 0 {
                    continue
                }
                grid[nr][nc] = 1
                q = append(q, [2]int{nr, nc})
            }
        }
        dist++
    }

    return -1
}
class Solution {
public:
    int shortestPathBinaryMatrix(vector<vector<int>>& grid) {
        int n = grid.size();
        if (grid[0][0] == 1 || grid[n - 1][n - 1] == 1) return -1;

        vector<pair<int,int>> dirs = {
            {-1,-1},{-1,0},{-1,1},{0,-1},{0,1},{1,-1},{1,0},{1,1}
        };

        queue<pair<int,int>> q;
        q.push({0, 0});
        grid[0][0] = 1;

        int dist = 1;
        while (!q.empty()) {
            int sz = q.size();
            while (sz--) {
                auto [r, c] = q.front(); q.pop();
                if (r == n - 1 && c == n - 1) return dist;

                for (auto [dr, dc] : dirs) {
                    int nr = r + dr, nc = c + dc;
                    if (nr < 0 || nr >= n || nc < 0 || nc >= n) continue;
                    if (grid[nr][nc] != 0) continue;
                    grid[nr][nc] = 1;
                    q.push({nr, nc});
                }
            }
            dist++;
        }

        return -1;
    }
};
from collections import deque
from typing import List

class Solution:
    def shortestPathBinaryMatrix(self, grid: List[List[int]]) -> int:
        n = len(grid)
        if grid[0][0] == 1 or grid[n - 1][n - 1] == 1:
            return -1

        dirs = [
            (-1, -1), (-1, 0), (-1, 1),
            (0, -1),           (0, 1),
            (1, -1),  (1, 0),  (1, 1),
        ]

        q = deque([(0, 0)])
        grid[0][0] = 1
        dist = 1

        while q:
            for _ in range(len(q)):
                r, c = q.popleft()
                if r == n - 1 and c == n - 1:
                    return dist

                for dr, dc in dirs:
                    nr, nc = r + dr, c + dc
                    if 0 <= nr < n and 0 <= nc < n and grid[nr][nc] == 0:
                        grid[nr][nc] = 1
                        q.append((nr, nc))
            dist += 1

        return -1
/**
 * @param {number[][]} grid
 * @return {number}
 */
var shortestPathBinaryMatrix = function(grid) {
  const n = grid.length;
  if (grid[0][0] === 1 || grid[n - 1][n - 1] === 1) return -1;

  const dirs = [
    [-1, -1], [-1, 0], [-1, 1],
    [0, -1],           [0, 1],
    [1, -1],  [1, 0],  [1, 1],
  ];

  const q = [[0, 0]];
  grid[0][0] = 1;
  let dist = 1;

  while (q.length) {
    const size = q.length;
    for (let i = 0; i < size; i++) {
      const [r, c] = q.shift();
      if (r === n - 1 && c === n - 1) return dist;

      for (const [dr, dc] of dirs) {
        const nr = r + dr, nc = c + dc;
        if (nr < 0 || nr >= n || nc < 0 || nc >= n || grid[nr][nc] !== 0) continue;
        grid[nr][nc] = 1;
        q.push([nr, nc]);
      }
    }
    dist++;
  }

  return -1;
};

中文

题目概述

给定一个 n x n 的二进制矩阵,从左上角走到右下角,求最短通路长度。只能走值为 0 的格子,且可以朝 8 个方向移动(含对角线)。

核心思路

这是无权图最短路问题,最适合 BFS。按层扩展时,层数就是当前路径长度。第一次到达终点时,一定是最短路径。

算法步骤

- 若起点或终点被阻塞,直接返回 -1
- 将 (0,0) 入队并标记已访问。
- 每层按 8 个方向扩展可达格子。
- 一旦到达 (n-1,n-1),返回当前层数。
- 队列耗尽仍未到达,返回 -1

复杂度分析

时间复杂度:O(n^2),每个格子最多访问一次。
空间复杂度:O(n^2),用于队列与访问标记。

常见陷阱

- 漏掉对角线方向,导致答案偏大或错误。
- 入队后不立即标记访问,造成重复入队。
- 路径长度计数从 0 开始,忽略起点应计为 1。

多语言参考实现(Java / Go / C++ / Python / JavaScript)

import java.util.*;

class Solution {
    public int shortestPathBinaryMatrix(int[][] grid) {
        int n = grid.length;
        if (grid[0][0] == 1 || grid[n - 1][n - 1] == 1) return -1;

        int[][] dirs = {
            {-1, -1}, {-1, 0}, {-1, 1},
            {0, -1},           {0, 1},
            {1, -1},  {1, 0},  {1, 1}
        };

        Queue q = new ArrayDeque<>();
        q.offer(new int[]{0, 0});
        grid[0][0] = 1;

        int dist = 1;
        while (!q.isEmpty()) {
            int size = q.size();
            for (int i = 0; i < size; i++) {
                int[] cur = q.poll();
                int r = cur[0], c = cur[1];
                if (r == n - 1 && c == n - 1) return dist;

                for (int[] d : dirs) {
                    int nr = r + d[0], nc = c + d[1];
                    if (nr < 0 || nr >= n || nc < 0 || nc >= n) continue;
                    if (grid[nr][nc] != 0) continue;
                    grid[nr][nc] = 1;
                    q.offer(new int[]{nr, nc});
                }
            }
            dist++;
        }
        return -1;
    }
}
func shortestPathBinaryMatrix(grid [][]int) int {
    n := len(grid)
    if grid[0][0] == 1 || grid[n-1][n-1] == 1 {
        return -1
    }

    dirs := [][2]int{{-1, -1}, {-1, 0}, {-1, 1}, {0, -1}, {0, 1}, {1, -1}, {1, 0}, {1, 1}}
    q := [][2]int{{0, 0}}
    grid[0][0] = 1
    dist := 1

    for len(q) > 0 {
        size := len(q)
        for i := 0; i < size; i++ {
            r, c := q[0][0], q[0][1]
            q = q[1:]
            if r == n-1 && c == n-1 {
                return dist
            }
            for _, d := range dirs {
                nr, nc := r+d[0], c+d[1]
                if nr < 0 || nr >= n || nc < 0 || nc >= n || grid[nr][nc] != 0 {
                    continue
                }
                grid[nr][nc] = 1
                q = append(q, [2]int{nr, nc})
            }
        }
        dist++
    }

    return -1
}
class Solution {
public:
    int shortestPathBinaryMatrix(vector<vector<int>>& grid) {
        int n = grid.size();
        if (grid[0][0] == 1 || grid[n - 1][n - 1] == 1) return -1;

        vector<pair<int,int>> dirs = {
            {-1,-1},{-1,0},{-1,1},{0,-1},{0,1},{1,-1},{1,0},{1,1}
        };

        queue<pair<int,int>> q;
        q.push({0, 0});
        grid[0][0] = 1;

        int dist = 1;
        while (!q.empty()) {
            int sz = q.size();
            while (sz--) {
                auto [r, c] = q.front(); q.pop();
                if (r == n - 1 && c == n - 1) return dist;

                for (auto [dr, dc] : dirs) {
                    int nr = r + dr, nc = c + dc;
                    if (nr < 0 || nr >= n || nc < 0 || nc >= n) continue;
                    if (grid[nr][nc] != 0) continue;
                    grid[nr][nc] = 1;
                    q.push({nr, nc});
                }
            }
            dist++;
        }

        return -1;
    }
};
from collections import deque
from typing import List

class Solution:
    def shortestPathBinaryMatrix(self, grid: List[List[int]]) -> int:
        n = len(grid)
        if grid[0][0] == 1 or grid[n - 1][n - 1] == 1:
            return -1

        dirs = [
            (-1, -1), (-1, 0), (-1, 1),
            (0, -1),           (0, 1),
            (1, -1),  (1, 0),  (1, 1),
        ]

        q = deque([(0, 0)])
        grid[0][0] = 1
        dist = 1

        while q:
            for _ in range(len(q)):
                r, c = q.popleft()
                if r == n - 1 and c == n - 1:
                    return dist

                for dr, dc in dirs:
                    nr, nc = r + dr, c + dc
                    if 0 <= nr < n and 0 <= nc < n and grid[nr][nc] == 0:
                        grid[nr][nc] = 1
                        q.append((nr, nc))
            dist += 1

        return -1
/**
 * @param {number[][]} grid
 * @return {number}
 */
var shortestPathBinaryMatrix = function(grid) {
  const n = grid.length;
  if (grid[0][0] === 1 || grid[n - 1][n - 1] === 1) return -1;

  const dirs = [
    [-1, -1], [-1, 0], [-1, 1],
    [0, -1],           [0, 1],
    [1, -1],  [1, 0],  [1, 1],
  ];

  const q = [[0, 0]];
  grid[0][0] = 1;
  let dist = 1;

  while (q.length) {
    const size = q.length;
    for (let i = 0; i < size; i++) {
      const [r, c] = q.shift();
      if (r === n - 1 && c === n - 1) return dist;

      for (const [dr, dc] of dirs) {
        const nr = r + dr, nc = c + dc;
        if (nr < 0 || nr >= n || nc < 0 || nc >= n || grid[nr][nc] !== 0) continue;
        grid[nr][nc] = 1;
        q.push([nr, nc]);
      }
    }
    dist++;
  }

  return -1;
};

Comments