这个题解采用了广度优先搜索(BFS)来找到获取所有钥匙的最短路径。首先,我们遍历整个网格以确定起点位置和所需收集的所有钥匙。每个钥匙对应一个二进制位,通过位操作来跟踪已收集的钥匙。搜索从起点开始,使用队列存储当前位置和已收集的钥匙状态。对于每个位置,我们尝试向四个方向移动,检查是否遇到墙壁、钥匙或锁。如果是钥匙,我们更新钥匙状态;如果是锁,我们检查是否已收集对应的钥匙。使用三维数组记录已访问的状态,以防止重复工作和无限循环。当收集到所有钥匙时,返回当前的步数。如果队列耗尽还未收集完所有钥匙,返回-1。
时间复杂度: O(m * n * 2^k)
空间复杂度: O(m * n * 2^k)
class Solution:
def shortestPathAllKeys(self, grid: List[str]) -> int:
m, n = len(grid), len(grid[0])
q = [] # BFS 队列
keys_to_find = 0 # 要找的钥匙的二进制表示
for i in range(m):
for j in range(n):
if grid[i][j] == '@':
q.append((i, j, 0)) # 起始位置及初始钥匙状态
elif grid[i][j].islower():
keys_to_find |= 1 << (ord(grid[i][j]) - ord('a')) # 统计所有钥匙
dirc = [(1, 0), (-1, 0), (0, 1), (0, -1)] # 四个方向
seen = [[[False] * (1 << 6) for _ in range(n)] for _ in range(m)] # 访问状态记录
step = 0 # 步数计数
while q:
size = len(q)
for _ in range(size):
x, y, collected_keys = q.pop(0)
if collected_keys == keys_to_find:
return step # 找到所有钥匙
for dx, dy in dirc:
nx, ny = x + dx, y + dy
if 0 <= nx < m and 0 <= ny < n:
cell = grid[nx][ny]
if cell == '#': # 墙
continue
elif cell.islower(): # 钥匙
new_collected_keys = collected_keys | (1 << (ord(cell) - ord('a')))
else:
new_collected_keys = collected_keys
if cell.isupper() and not (new_collected_keys & (1 << (ord(cell.lower()) - ord('a')))):
continue # 没有对应的钥匙
if not seen[nx][ny][new_collected_keys]:
seen[nx][ny][new_collected_keys] = True
q.append((nx, ny, new_collected_keys))
step += 1
return -1 # 如果无法收集所有钥匙