问题描述
小S在一个n×mn×m的网格迷宫中,初始位置在左上角 (1,1)(1,1),目标是到达右下角 (n,m)(n,m)。每个格子可以是黑色(表示为1)或者白色(表示为0)。他希望在移动过程中经过的黑色格子尽可能少。移动时可以向上、下、左、右四个方向移动,但不能走出迷宫的边界。请你帮小S计算从起点到终点所需经过的最少黑色格子的数量。
测试样例
样例1:
输入:
n = 5 ,m = 3 ,grid = [[0, 1, 0], [0, 1, 1], [0, 1, 0], [1, 0, 0], [1, 0, 0]]
输出:1
样例2:
输入:
n = 4 ,m = 4 ,grid = [[0, 0, 1, 0], [1, 0, 1, 0], [1, 0, 0, 0], [1, 1, 1, 0]]
输出:0
样例3:
输入:
n = 3 ,m = 3 ,grid = [[0, 0, 0], [1, 1, 0], [1, 1, 0]]
输出:0
关键点
- 网格迷宫:迷宫是一个二维网格,每个格子可以是黑色(1)或白色(0)。
- 起点和终点:起点是左上角 ,终点是右下角 。
- 移动规则:可以向上、下、左、右四个方向移动,但不能走出迷宫的边界。
- 目标:找到从起点到终点的路径,使得经过的黑色格子数量最少。
代码分析
- 定义四个方向的移动
directions = [(-1, 0), (1, 0), (0, -1), (0, 1)]
- 初始化队列和访问标记数组
queue = deque([(0, 0)]) # 起点 (0, 0)
visited = [[float('inf')] * m for _ in range(n)]
- 记录每个格子到起点的最小黑色格子数量
visited[0][0] = 0 if grid[0][0] == 0 else 1 # 起点如果是黑色格子,初始值为1,否则为0
while queue:
x, y = queue.popleft()
# 检查四个方向的相邻格子
for dx, dy in directions:
nx, ny = x + dx, y + dy
# 检查是否越界
if 0 <= nx < n and 0 <= ny < m:
# 计算相邻格子到起点的黑色格子数量
new_cost = visited[x][y] + (1 if grid[nx][ny] == 1 else 0)
# 如果新路径更优,更新并加入队列
if new_cost < visited[nx][ny]:
visited[nx][ny] = new_cost
queue.append((nx, ny))
- 返回终点到起点的最小黑色格子数量
return visited[n-1][m-1]
完整代码演示
from collections import deque
def solution(n: int, m: int, grid: list) -> int:
directions = [(-1, 0), (1, 0), (0, -1), (0, 1)]
queue = deque([(0, 0)])
visited = [[float('inf')] * m for _ in range(n)]
visited[0][0] = 0 if grid[0][0] == 0 else 1
while queue:
x, y = queue.popleft()
for dx, dy in directions:
nx, ny = x + dx, y + dy
if 0 <= nx < n and 0 <= ny < m:
new_cost = visited[x][y] + (1 if grid[nx][ny] == 1 else 0)
if new_cost < visited[nx][ny]:
visited[nx][ny] = new_cost
queue.append((nx, ny))
return visited[n-1][m-1]
解题思路
- 理解问题:需要在网格中找到从起点到终点的路径,使得经过的黑色格子数量最少。
- 数据结构选择:
- 使用队列来进行BFS。
- 使用一个二维数组来记录每个格子到起点的最小黑色格子数量。
- 算法步骤:
- 初始化队列,将起点加入队列,并记录起点到起点的黑色格子数量为0。
- 从队列中取出当前格子,检查其四个方向的相邻格子。
- 如果相邻格子是有效的(不越界且未访问过),则更新其到起点的黑色格子数量,并将其加入队列。
- 重复上述步骤,直到队列为空或到达终点。
关键步骤解释
- 方向数组:
directions用于表示四个方向的移动。 - 队列和访问标记数组:
queue用于BFS,visited用于记录每个格子到起点的最小黑色格子数量。 - BFS循环:从队列中取出当前格子,检查其相邻格子,更新最小黑色格子数量并加入队列。
- 返回结果:最终返回终点到起点的最小黑色格子数量。
总结
通过这个题目能够加深对BFS算法的理解,还能掌握二维数组的操作、队列的使用、动态规划思想以及复杂度分析。这些技能在解决许多其他类似的网格问题和图问题时都非常有用。