LeetCode #1091 二进制矩阵中的最短路径
题目描述
在一个 N × N 的方形网格中,每个单元格有两种状态:空(0)或者阻塞(1)。
一条从左上角到右下角、长度为 k 的畅通路径,由满足下述条件的单元格 C_1, C_2, ..., C_k
组成:
相邻单元格 C_i
和 C_{i+1}
在八个方向之一上连通(此时,C_i
和 C_{i+1}
不同且共享边或角)
C_1 位于 (0, 0)
(即,值为 grid[0][0]
)
C_k 位于 (N-1, N-1)
(即,值为 grid[N-1][N-1]
)
如果 C_i 位于 (r, c)
,则 grid[r][c]
为空(即,grid[r][c] == 0
)
返回这条从左上角到右下角的最短畅通路径的长度。如果不存在这样的路径,返回 -1 。
示例 1:
输入:[[0,1],[1,0]]
输出:2
示例 2:
输入:[[0,0,0],[1,1,0],[1,1,0]]
输出:4
提示:
1 <= grid.length == grid[0].length <= 100
grid[i][j]
为0
或1
思路分析
标准的 BFS 思路,用于求图中的最短路径,模板如下:
def BFS()
{
定义队列;
定义备忘录,用于记录已经访问的位置;
判断边界条件,是否能直接返回结果的。
将起始位置加入到队列中,同时更新备忘录。
while 队列不为空 {
获取当前队列中的元素个数。
for 元素个数 {
取出一个位置节点。
判断是否到达终点位置。
获取它对应的下一个所有的节点。
条件判断,过滤掉不符合条件的位置。
新位置重新加入队列。
}
}
}
程序实现 BFS 需要考虑以下问题:
- 队列:用来存储每一轮遍历得到的节点
- 标记:对于遍历过的节点,应该将它标记,放置重复遍历
class Solution:
def shortestPathBinaryMatrix(self, grid: List[List[int]]) -> int:
n = len(grid) - 1
if not grid or grid[0][0] == 1 or grid[n][n] == 1:
return -1
elif len(grid) <= 1:
return n + 1
direction = [(-1,-1), (1,0), (0,1), (-1,0), (0,-1), (1,1), (1,-1), (-1,1)]
queue = []
queue.append((0, 0, 1))
# 相当于标记为visited,后面不会再访问
grid[0][0] = 1
while queue:
# 每次取队头,这样可以保证第一次退出的时候就最短路径
x, y, step = queue.pop(0)
for dx, dy in direction:
if x + dx == n and y + dy == n:
return step + 1
if 0 <= x + dx <= n and 0 <= y + dy <= n and grid[x+dx][y+dy] == 0:
queue.append((x+dx, y+dy, step+1))
grid[x+dx][y+dy] = 1
return -1