问题描述
小R最近在玩一个迷宫游戏,游戏的目标是在一个 n x n 的二进制矩阵 grid 中找到一条从左上角 (0, 0) 到右下角 (n - 1, n - 1) 的畅通路径。畅通路径必须满足以下条件:
- 路径经过的所有单元格的值都是
0。 - 路径中相邻的单元格必须在 8 个方向之一上连通(相邻单元格之间共享一条边或一个角)。
你需要帮助小R找到最短的畅通路径长度。如果不存在这样的路径,返回 -1。
解题思路
我们需要在一个 n x n 的二进制矩阵 grid 中找到一条从左上角 (0, 0) 到右下角 (n - 1, n - 1) 的最短畅通路径。畅通路径必须满足以下条件:
- 路径经过的所有单元格的值都是
0。 - 路径中相邻的单元格必须在 8 个方向之一上连通(相邻单元格之间共享一条边或一个角)。
算法步骤
-
初始化 BFS 队列:我们需要一个队列来存储当前正在处理的单元格及其路径长度。队列的初始元素是起始点
(0, 0)和路径长度1。 -
处理边界条件:如果起始点
(0, 0)或目标点(n-1, n-1)是障碍(即值为1),则直接返回-1。 -
定义移动方向:由于路径可以在 8 个方向上移动,我们需要定义一个包含所有可能移动方向的列表。
-
BFS 主循环:
- 从队列中取出当前单元格。
- 检查是否到达目标点
(n-1, n-1),如果是则返回当前路径长度。 - 否则,将当前单元格标记为已访问(例如,将其值设为
1),并将其所有未访问的相邻单元格加入队列。
-
处理无解情况:如果 BFS 队列为空且未找到路径,则返回
-1。
代码
from collections import deque
def solution(grid: list) -> int:
n = len(grid)
# 处理边界条件
if grid[0][0] == 1 or grid[n-1][n-1] == 1:
return -1
# 定义8个方向的移动
directions = [(-1, 0), (1, 0), (0, -1), (0, 1), (-1, -1), (-1, 1), (1, -1), (1, 1)]
# 初始化BFS队列
queue = deque([(0, 0, 1)]) # (row, col, path_length)
grid[0][0] = 1 # 标记起始点为已访问
while queue:
row, col, path_length = queue.popleft()
# 检查是否到达目标点
if row == n-1 and col == n-1:
return path_length
# 探索所有8个方向
for dr, dc in directions:
new_row, new_col = row + dr, col + dc
# 检查新位置是否在网格内且未访问
if 0 <= new_row < n and 0 <= new_col < n and grid[new_row][new_col] == 0:
queue.append((new_row, new_col, path_length + 1))
grid[new_row][new_col] = 1 # 标记为已访问
# 如果BFS结束仍未找到路径,返回-1
return -1
if __name__ == '__main__':
print(solution(grid=[[0, 1], [1, 0]]) == 2)
print(solution(grid=[[0, 0, 0], [1, 1, 0], [1, 1, 0]]) == 4)
print(solution(grid=[[1, 0, 0], [1, 1, 0], [1, 1, 0]]) == -1)