当前:LC1091 · 二进制矩阵中的最短路径 · 首次出现于 Day 30 · 路径:顶栏「56天打卡」→ 点击 LC 题号 → 逐题动画

LC1091 · Shortest Path in Binary Matrix · 网格 / BFS

二进制矩阵最短路径:八个方向,一层一步

0 可走、1 阻塞。每步可走八邻域。无权图的最短格子数就是 BFS 层数;第一次弹出右下角即答案。

起点或终点是 1 则 −1。从 (0,0) 入队,步数从 1 计(路径含起点)。按层扩展 8 个方向,走进 0 就原地置 1。弹出 (n−1,n−1) 时返回当前步数。队列空则 −1。时间 O(n²),空间 O(n²)。

时间 O(n²)空间 O(n²)结论先行 · 全文约 6 节
导读

这是 LeetCode 1091. Shortest Path in Binary Matrix。n×n 的网格,0 能走、1 不能走。从左上 (0,0) 走到右下 (n−1,n−1),每一步可以走到相邻 8 格(含对角)。返回路径上的格子数;走不到返回 −1。

主例是 3×3:四周一圈 0,正中 (1,1) 是 1。不能斜穿中心走 3 格。一条最短路是 (0,0)→(0,1)→(1,2)→(2,2),长度 4。演示按层标出步 1、步 2、步 3 的前沿,最后给出 4。

第一直觉是 DFS 搜所有路径取最短。网格一大约指数爆炸,还容易和「能走到」搞混。缺的是无权图里「先到的一定更短」。下面从这块缺口用 BFS 分层。

八邻域不改变「先到即最短」

路径长度按经过的格子数算,每走一格 +1,对角和上下左右代价相同。这是无权图。起点也算进长度,所以从 (0,0) 出发时步数是 1,不是 0。单独一格的 1×1 且值为 0,答案是 1。

缺的信息是「第一次到达终点用了几步」。DFS 先走一条绕远的,再走一条近的,必须全局比;还要防止在 0 的空地里转圈。BFS 按距起点的步数分层:第 k 层都是最少 k 步能到的格子。第一次从队列里拿出终点,k 就是最短。

从缺口写出 8 方向 BFS。起点或终点为 1,直接 −1。队列放 (0,0),把起点改成 1 当访问标记。每轮先记下本层 size,弹出一个格子,若是终点返回 steps;否则把八个邻居里仍为 0 的改成 1 并入队。一层处理完 steps+1。方向向量是 (±1,0)、(0,±1)、(±1,±1) 共八个。

用手走主例。步 1,前沿只有 (0,0)。它的八邻里合法且为 0 的是 (0,1) 和 (1,0);(1,1) 是障碍。步 2,前沿 [(0,1),(1,0)]。再扩一层,演示标出绕过中心后的 (1,2)、(2,0)、(2,1)。步 3 还没踩到终点。再走一步第一次到达 (2,2),返回 4。

访问必须入队时标记,不能弹出再标,否则同一格会进队多次。不要把长度理解成边数:题目要格子数,代码里 steps 从 1 起。四方向版本会变题。每格最多入队一次,时间 O(n²)。

对角不是捷径特权对角一步仍只 +1,所以有时比先横再竖短。主例中心被堵,对角 (0,0)→(1,1)→(2,2) 不合法,最短仍是 4,不是 3。
3×3,最短路径
·
·
·
·
·
·
·
·
1步 1:起点 (0,0)

Go:8 方向 BFS

solution.goGo
func shortestPathBinaryMatrix(grid [][]int) int {
n := len(grid)
if grid[0][0] != 0 || grid[n-1][n-1] != 0 { return -1 }
q := [][2]int{{0, 0}}
grid[0][0] = 1
steps := 1
dirs := [8][2]int{{-1,-1},{-1,0},{-1,1},{0,-1},{0,1},{1,-1},{1,0},{1,1}}
for len(q) > 0 {
size := len(q)
for k := 0; k < size; k++ {
cur := q[0]; q = q[1:]
if cur[0] == n-1 && cur[1] == n-1 { return steps }
for _, d := range dirs {
ni, nj := cur[0]+d[0], cur[1]+d[1]
if ni >= 0 && ni < n && nj >= 0 && nj < n && grid[ni][nj] == 0 {
grid[ni][nj] = 1
q = append(q, [2]int{ni, nj})
}
}
}
steps++
}
return -1
}

1首尾不是 0,没有路径。1×1 的 [0] 会在弹出起点时返回 1。

2grid[i][j]=1 表示来过。入队即标记,避免同层重复入队。

3size 切层。主例步 1 只处理 (0,0),步 2 处理 (0,1) 和 (1,0)。

4八个方向写全。弹出终点才返回 steps,主例是 4。

总结

8 向 BFS,层数即格子数。主例中心挡住斜穿,最短 4。

  • 对角合法,但不等于可以踩 1。主例 (1,1) 进不去,所以不是 3。
  • steps 从 1 计,因为长度含起点。
  • 入队时置 1。队列空仍没弹出终点,返回 −1。
同族题目
LC200岛屿数量LC994腐烂的橘子LC127单词接龙