LeetCode 864. 获取所有钥匙的最短路径
字数 1944 2025-12-07 00:00:11
LeetCode 864. 获取所有钥匙的最短路径
题目描述
你站在一个二维的网格地图中,其中:
'.'代表可以通行的空地。'#'代表墙,不能通过。- 小写字母(
'a'到'f')表示钥匙。 - 大写字母(
'A'到'F')表示锁,需要对应的钥匙(小写字母)才能通过。 '@'是你的起始位置。
你从起点出发,可以上下左右移动(不能移出网格)。你需要收集所有钥匙,并希望用最少的移动步数完成。返回收集所有钥匙所需的最少移动步数;如果不可能收集所有钥匙,返回 -1。
注意:
- 钥匙数量范围是 1 到 6,分别对应
'a'到'f'。 - 锁的字母与对应钥匙的字母相同(例如,锁 'A' 需要钥匙 'a')。
- 钥匙可以重复通过同一个格子。
- 保证起点
'@'是空地。
示例:
网格:["@.a.#","###.#","b.A.B"]
地图:
@ . a . #
# # # . #
b . A . B
起点是 (0,0)。钥匙是 'a' 和 'b',锁是 'A' 和 'B'。你需要拿到钥匙 'a' 打开锁 'A',然后拿到钥匙 'b' 打开锁 'B'。一种最短路径是:右移拿到 'a',下移、下移、左移拿到 'b',然后右移、上移、右移、右移通过终点。总步数是 8。
解题过程循序渐进讲解
1. 问题分析
这是一个在网格中寻找最短路径的问题,但状态不仅包括位置,还包括当前已经获得的钥匙集合,因为钥匙决定了能否通过对应的锁。因此,我们需要在状态空间中进行搜索。状态可以定义为 (x, y, keys),其中 (x, y) 是当前位置,keys 是一个二进制掩码表示当前拥有的钥匙集合(因为钥匙最多 6 把,可以用 6 位二进制表示,每位代表对应钥匙是否已获得)。
2. 状态表示
- 用
(x, y, mask)表示一个状态,其中mask是一个整数,其二进制从低到高分别表示是否拥有钥匙 'a' 到 'f'。例如,mask = 0b000011表示拥有钥匙 'a' 和 'b'。 - 我们需要记录从起点到每个状态的最短步数,通常用 BFS 来保证首次到达目标状态时步数最小。
3. BFS 搜索过程
- 起点状态为
(start_x, start_y, 0),步数为 0。 - 使用队列进行 BFS,同时用一个集合或哈希表记录访问过的状态
(x, y, mask)以避免重复访问。 - 在每一步,从队列中取出一个状态,尝试向四个方向移动:
- 如果新位置在网格内且不是墙
'#',则检查该位置的字符:- 如果是空地
'.'或起点'@':直接允许移动,钥匙状态不变。 - 如果是小写字母(钥匙):则更新钥匙状态,将对应位置 1(
new_mask = mask | (1 << (ch - 'a')))。 - 如果是大写字母(锁):检查是否有对应钥匙,即
(mask >> (ch - 'A')) & 1是否为 1,如果有则允许通过,否则不能移动。
- 如果是空地
- 如果新位置在网格内且不是墙
- 如果新状态
(new_x, new_y, new_mask)没有被访问过,则将其加入队列,并记录步数。 - 当 BFS 过程中遇到某个状态的钥匙集合包含了所有钥匙(即
new_mask == target_mask,其中target_mask是所有钥匙都拥有的掩码),则立即返回当前步数 + 1(因为从当前状态移动到新位置算一步)。
4. 详细步骤示例
以示例网格为例:
网格:["@.a.#","###.#","b.A.B"]
步骤:
- 扫描网格,找到起点 (0,0),统计钥匙数量为 2('a' 在 (0,2),'b' 在 (2,0))。目标掩码
target_mask = 0b11(即 3)。 - BFS 初始化:队列起始状态为
(0,0,0),步数 0。 - 从 (0,0,0) 开始,尝试移动:
- 向右到 (0,1):空地,状态
(0,1,0)入队。 - 向下到 (1,0):是墙
'#',跳过。
- 向右到 (0,1):空地,状态
- 继续 BFS 扩展。当移动到 (0,2) 时,遇到钥匙 'a',更新掩码为
0b01。继续搜索直到获得钥匙 'b' 并打开所有锁。 - 当某个状态的掩码变为
0b11时,表示已获得所有钥匙,返回当前步数。
5. 复杂度与优化
- 网格大小最多 30x30,钥匙最多 6 把,状态总数最多 30302^6 = 57600,BFS 可在该范围内完成。
- 使用位运算高效处理钥匙和锁的检查。
6. 边界情况
- 没有钥匙时直接返回 0。
- 钥匙被墙包围无法获取时返回 -1。
- 锁和钥匙可能分布在多个区域,需通过 BFS 探索所有可能路径。
总结
本题的关键在于将钥匙持有情况作为状态的一部分,从而将问题转化为在状态空间上的最短路径搜索,通过 BFS 找到首次获得所有钥匙的状态即为最短路径。状态设计和位运算的使用是解题的核心技巧。