LeetCode 题解工作台
穿过迷宫的最少移动次数
你还记得那条风靡全球的贪吃蛇吗? 我们在一个 n*n 的网格上构建了新的迷宫地图,蛇的长度为 2,也就是说它会占去两个单元格。蛇会从左上角( (0, 0) 和 (0, 1) )开始移动。我们用 0 表示空单元格,用 1 表示障碍物。蛇需要移动到迷宫的右下角( (n-1, n-2) 和 (n-1, n…
3
题型
6
代码语言
3
相关题
当前训练重点
困难 · 图·搜索
答案摘要
题目求的是蛇从起始位置到达目标位置的最少移动次数,我们考虑使用广度优先搜索 来求解。 我们定义以下数据结构或变量:
Interview AiBoxInterview AiBox 实时 AI 助手,陪你讲清 图·搜索 题型思路
题目描述
你还记得那条风靡全球的贪吃蛇吗?
我们在一个 n*n 的网格上构建了新的迷宫地图,蛇的长度为 2,也就是说它会占去两个单元格。蛇会从左上角((0, 0) 和 (0, 1))开始移动。我们用 0 表示空单元格,用 1 表示障碍物。蛇需要移动到迷宫的右下角((n-1, n-2) 和 (n-1, n-1))。
每次移动,蛇可以这样走:
- 如果没有障碍,则向右移动一个单元格。并仍然保持身体的水平/竖直状态。
- 如果没有障碍,则向下移动一个单元格。并仍然保持身体的水平/竖直状态。
- 如果它处于水平状态并且其下面的两个单元都是空的,就顺时针旋转 90 度。蛇从(
(r, c)、(r, c+1))移动到 ((r, c)、(r+1, c))。

- 如果它处于竖直状态并且其右面的两个单元都是空的,就逆时针旋转 90 度。蛇从(
(r, c)、(r+1, c))移动到((r, c)、(r, c+1))。

返回蛇抵达目的地所需的最少移动次数。
如果无法到达目的地,请返回 -1。
示例 1:

输入:grid = [[0,0,0,0,0,1],
[1,1,0,0,1,0],
[0,0,0,0,1,1],
[0,0,1,0,1,0],
[0,1,1,0,0,0],
[0,1,1,0,0,0]]
输出:11
解释:
一种可能的解决方案是 [右, 右, 顺时针旋转, 右, 下, 下, 下, 下, 逆时针旋转, 右, 下]。
示例 2:
输入:grid = [[0,0,1,1,1,1], [0,0,0,0,1,1], [1,1,0,0,0,1], [1,1,1,0,0,1], [1,1,1,0,0,1], [1,1,1,0,0,0]] 输出:9
提示:
2 <= n <= 1000 <= grid[i][j] <= 1- 蛇保证从空单元格开始出发。
解题思路
方法一:BFS
题目求的是蛇从起始位置到达目标位置的最少移动次数,我们考虑使用广度优先搜索 来求解。
我们定义以下数据结构或变量:
- 队列 :存储蛇的当前位置,每个位置是一个二元组 ,其中 表示蛇的尾部位置,而 表示蛇的头部位置。初始时,我们将位置 加入队列 中。如果我们将二维迷宫扁平化成一个一维数组,那么位置 就表示一维数组下标为 和 的两个单元格。
- 目标位置 :值固定为 ,即二维迷宫的最后一行的最后两个单元格。
- 数组或集合 :存储蛇的当前位置状态是否已经被访问过,每个状态是一个二元组 ,其中 表示蛇的尾部位置;而 表示蛇当前所处的状态,取值为 或 ,分别表示蛇的水平状态和垂直状态。初始时将起始位置 的状态加入集合 中。
- 答案变量 :存储蛇从起始位置到达目标位置的移动次数,初始时为 。
我们使用广度优先搜索来求解,每次从队列 中取出一个位置,判断该位置是否为目标位置 ,如果是,则直接返回答案变量 。如果不是,则将该位置的下一个可能的位置加入队列 中,并将该位置加入 中。注意,这里的下一个位置可能是蛇的水平状态或垂直状态,我们需要分别判断(具体见以下代码注释)。在每一轮搜索结束后,答案变量 自增 。
最后,如果队列 为空,说明无法从起始位置到达目标位置,返回 。
时间复杂度 ,空间复杂度 。其中 是二维迷宫的行数或列数。
class Solution:
def minimumMoves(self, grid: List[List[int]]) -> int:
def move(i1, j1, i2, j2):
if 0 <= i1 < n and 0 <= j1 < n and 0 <= i2 < n and 0 <= j2 < n:
a, b = i1 * n + j1, i2 * n + j2
status = 0 if i1 == i2 else 1
if (a, status) not in vis and grid[i1][j1] == 0 and grid[i2][j2] == 0:
q.append((a, b))
vis.add((a, status))
n = len(grid)
target = (n * n - 2, n * n - 1)
q = deque([(0, 1)])
vis = {(0, 0)}
ans = 0
while q:
for _ in range(len(q)):
a, b = q.popleft()
if (a, b) == target:
return ans
i1, j1 = a // n, a % n
i2, j2 = b // n, b % n
# 尝试向右平移(保持身体水平/垂直状态)
move(i1, j1 + 1, i2, j2 + 1)
# 尝试向下平移(保持身体水平/垂直状态)
move(i1 + 1, j1, i2 + 1, j2)
# 当前处于水平状态,且 grid[i1 + 1][j2] 无障碍,尝试顺时针旋转90°
if i1 == i2 and i1 + 1 < n and grid[i1 + 1][j2] == 0:
move(i1, j1, i1 + 1, j1)
# 当前处于垂直状态,且 grid[i2][j1 + 1] 无障碍,尝试逆时针旋转90°
if j1 == j2 and j1 + 1 < n and grid[i2][j1 + 1] == 0:
move(i1, j1, i1, j1 + 1)
ans += 1
return -1
复杂度分析
| 指标 | 值 |
|---|---|
| 时间 | complexity is O(n^2 * 2) considering all positions and orientations. Space complexity is also O(n^2 * 2) for visited states and BFS queue storage. |
| 空间 | Depends on the final approach |
面试官常问的追问
外企场景- question_mark
Candidate must correctly track snake orientation and positions separately.
- question_mark
Look for BFS usage to ensure minimal moves are found instead of DFS.
- question_mark
Check that rotations only occur when the required 2x2 space is empty.
常见陷阱
外企场景- error
Failing to account for orientation when checking valid moves.
- error
Forgetting to mark states as visited leading to cycles in BFS.
- error
Attempting rotations without verifying all necessary cells are empty.
进阶变体
外企场景- arrow_right_alt
Snake length can be extended to more than 2 cells with similar BFS logic.
- arrow_right_alt
Allow diagonal moves and rotations for more complex maneuvering.
- arrow_right_alt
Introduce weighted moves where certain directions cost more, adjusting BFS to Dijkstra.