力扣——864. 获取所有钥匙的最短路径

117 阅读1分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第6天,点击查看活动详情

力扣——864. 获取所有钥匙的最短路径

864. 获取所有钥匙的最短路径

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

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

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

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

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

示例 1:

img

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

示例 2:

img

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

提示:

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

问题解析

很正常的BFS。

大致思路就是BFS的过程中记录拿到钥匙的情况,当遇到锁的情况只要看有没有对应的钥匙就可以知道能不能走过,当拿到所有钥匙后返回步数,如果BFS结束了也没有返回步数,说明拿不到全部的钥匙,返回-1。

至于记录拿到钥匙,因为钥匙最多只有6个,我们可以用二进制的方式来记录状态,二进制下初始为000000,0表示第i个钥匙没拿到,1表示拿到了,当我们拿到哪个钥匙后,就把哪个位置的二进制变为1。遇到锁了只要看对应位置的二进制是否为1即可。

用一个三维数组st记录bfs走过的位置情况,st[i] [j] [k]表示是否以钥匙状态为k时,走到第i行第j列。

AC代码

class Solution {
public:
    int dx[4] = { 1,0,-1,0 }, dy[4] = { 0,1,0,-1 };
    int st[50][50][100];
    int shortestPathAllKeys(vector<string>& grid) {
        int cnt = 0, x, y, n = grid.size(), m = grid[0].size();
        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < m; j++)
            {
                if (grid[i][j] >= 'a' && grid[i][j] <= 'z')cnt++;
                else if (grid[i][j] == '@')x = i, y = j;
            }
        }
        int res = (1 << cnt) - 1;
        queue<vector<int>>que;
		
		//第一个0表示钥匙状态,第2个0表示走过的步数
        que.push({ x,y,0,0 });
        st[x][y][0] = 1;
        while (!que.empty())
        {
            int len = que.size();
            for (int i = 0; i < len; i++)
            {
                x = que.front()[0], y = que.front()[1];
                int num = que.front()[2], ans = que.front()[3];
                que.pop();
                if (num == res)return ans;
                for (int j = 0; j < 4; j++)
                {
                    int a = dx[j] + x, b = dy[j] + y;
                    if (a >= 0 && a < n && b >= 0 && b < m && grid[a][b] != '#' && !st[a][b][num])
                    {
                    	//如果遇到锁的位置,则看也没有对应的钥匙,如果没有就走不到这个位置
                        if (grid[a][b] >= 'A' && grid[a][b] <= 'Z' && !((num >> (grid[a][b] - 'A')) & 1))
                            continue;
                        //如果遇到钥匙,改变所持钥匙的状态
                        else if (grid[a][b] >= 'a' && grid[a][b] <= 'z' && !((num >> (grid[a][b] - 'a')) & 1))
                        {
                            que.push({ a,b,num + (1 << (grid[a][b] - 'a')),ans + 1 });
                            st[a][b][num + (1 << (grid[a][b] - 'a'))] = 1;
                        }
                        else
                        {
                            que.push({ a,b,num,ans + 1 });
                            st[a][b][num] = 1;
                        }

                    }
                }
            }
        }
        return -1;
    }
};