目录

0864:获取所有钥匙的最短路径(2258 分)

力扣第 92 场周赛第 4 题

题目

给定一个二维网格 grid ,其中:

  • '.' 代表一个空房间
  • '#' 代表一堵墙
  • '@' 是起点
  • 小写字母代表钥匙
  • 大写字母代表锁

我们从起点开始出发,一次移动是指向四个基本方向之一行走一个单位空间。我们不能在网格外面行走,也无法穿过一堵墙。如果途经一个钥匙,我们就把它捡起来。除非我们手里有对应的钥匙,否则无法通过锁。

假设 k 为 钥匙/锁 的个数,且满足 1 <= k <= 6,字母表中的前 k 个字母在网格中都有自己对应的一个小写和一个大写字母。换言之,每个锁有唯一对应的钥匙,每个钥匙也有唯一对应的锁。另外,代表钥匙和锁的字母互为大小写并按字母顺序排列。

返回获取所有钥匙所需要的移动的最少次数。如果无法获取所有钥匙,返回 -1

示例 1:

输入:grid = ["@.a..","###.#","b.A.B"]
输出:8
解释:目标是获得所有钥匙,而不是打开所有锁。

示例 2:

输入:grid = ["@..aA","..B#.","....b"]
输出:6

示例 3:

输入: grid = ["@Aa"]
输出: -1

提示:

  • m == grid.length
  • n == grid[i].length
  • 1 <= m, n <= 30
  • grid[i][j] 只含有 '.', '#', '@', 'a'-'f' 以及 'A'-'F'
  • 钥匙的数目范围是 [1, 6]
  • 每个钥匙都对应一个 不同 的字母
  • 每个钥匙正好打开一个对应的锁

分析

#1

将状态 <位置,钥匙集合> 看作顶点,就是典型的 bfs 问题,遍历即可。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
class Solution:
    def shortestPathAllKeys(self, grid: List[str]) -> int:
        m, n = len(grid), len(grid[0])
        d = {grid[i][j]:(i,j) for i in range(m) for j in range(n)}
        si, sj = d['@']
        tg = sum(1<<i for i in range(6) if chr(ord('a')+i) in d)
        Q, vis = deque([(0,si,sj,0)]), {(si,sj,0)}
        while Q:
            w,i,j,st = Q.popleft()
            if st==tg:
                return w
            for x,y in [(i+1,j),(i-1,j),(i,j+1),(i,j-1)]:
                if 0<=x<m and 0<=y<n and grid[x][y]!='#':
                    c = grid[x][y]
                    if c in 'ABCDEF' and not st&1<<(ord(c)-ord('A')):
                        continue
                    st2 = st|1<<(ord(c)-ord('a')) if c in 'abcdef' else st
                    if (x,y,st2) not in vis:
                        Q.append((w+1,x,y,st2))
                        vis.add((x,y,st2))
        return -1

183 ms

#2

  • 注意到只有钥匙和锁的位置是重要的,它们之间的距离是固定的
  • 因此建立新图,只包含起点和钥匙、锁的位置,预处理它们之间的距离
    • 注意预处理时不能越过锁,但要记录到锁的距离
  • 仍然以状态 <位置,钥匙集合> 作为顶点,变为典型的最短路问题,用 dijkstra 即可

解答

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
class Solution:
    def shortestPathAllKeys(self, grid: List[str]) -> int:
        def bfs(i,j):
            Q = deque([(0,i,j)])
            d = defaultdict(lambda:inf)
            d[(i,j)] = 0
            while Q:
                w,i,j = Q.popleft()
                for x,y in [(i+1,j),(i-1,j),(i,j+1),(i,j-1)]:
                    if 0<=x<m and 0<=y<n and grid[x][y]!='#' and (x,y) not in d:
                        d[(x,y)] = w+1
                        if grid[x][y] not in 'ABCDEF':
                            Q.append((w+1,x,y))
            return [d[(x,y)] for x,y in A]

        m,n = len(grid),len(grid[0])
        g = defaultdict(list)
        for i,j in product(range(m),range(n)):
            g[grid[i][j]].append((i,j))
        tg = sum(1<<i for i in range(6) if chr(ord('a')+i) in g)
        A = [(i,j) for c in '@abcdefABCDEF' for i,j in g[c]]
        f = [bfs(i,j) for i,j in A]
        pq = [(0,0,0)]
        d = defaultdict(lambda:inf)
        d[(0,0)] = 0
        while pq:
            w,u,st = heappop(pq)
            if st==tg:
                return w
            if w>d[(u,st)]:
                continue
            for v,(i,j) in enumerate(A):
                c = grid[i][j]
                if c in 'ABCDEF' and not st&1<<(ord(c)-ord('A')):
                    continue
                w2 = w+f[u][v]
                st2 = st|1<<(ord(c)-ord('a')) if c in 'abcdef' else st
                if w2<d[(v,st2)]:
                    d[(v,st2)]=w2
                    heappush(pq,(w2,v,st2))
        return -1

71 ms