题目描述:
给定一个二维网格 grid ,其中:
'.' 代表一个空房间
'#' 代表一堵
'@' 是起点
小写字母代表钥匙
大写字母代表锁
我们从起点开始出发,一次移动是指向四个基本方向之一行走一个单位空间。我们不能在网格外面行走,也无法穿过一堵墙。如果途经一个钥匙,我们就把它捡起来。除非我们手里有对应的钥匙,否则无法通过锁。
假设 k 为 钥匙/锁 的个数,且满足 1 <= k <= 6,字母表中的前 k 个字母在网格中都有自己对应的一个小写和一个大写字母。换言之,每个锁有唯一对应的钥匙,每个钥匙也有唯一对应的锁。另外,代表钥匙和锁的字母互为大小写并按字母顺序排列。
返回获取所有钥匙所需要的移动的最少次数。如果无法获取所有钥匙,返回 -1 。
Level | AC rate |
Hard | 59.8% |
题目解析:
难得很!!看了答案过后勉强磕磕绊绊写出来了,在迷宫中实现了广度优先遍历搜索,使用一个三维矩阵,分别为数据点的行坐标、列坐标和状态表达式,矩阵的值为当前点对应的行动步数。所谓状态表达式就是目前拥有的钥匙数,使用位运算,将每个钥匙使用对应位置置1表示,当状态表达式和所有位都为1的值相同时,表明拿到了所有钥匙,返回当前步数即可,需要注意的是,当遇到箱子时需要对手上的钥匙进行判断,并且每一步都需要在当前对应点没有被走过的情况下进行行动,代码如下:
class Solution {
public:
int shortestPathAllKeys(vector<string>& grid) {
vector<vector<int>> direction{{-1,0},{1,0},{0,-1},{0,1}};
int m = grid.size();
int n = grid[0].length();
int sx = 0;
int sy = 0;
unordered_map<char,int> k2p;
for(int i = 0 ; i<m ; i++){
for(int j = 0 ; j<n ; j++){
if(grid[i][j]=='@'){
sx = i;
sy = j;
}
else if(islower(grid[i][j])){
if(!k2p.count(grid[i][j])){
int idx = k2p.size();
k2p[grid[i][j]] = idx;
}
}
}
}
queue<tuple<int, int, int>> q;
vector<vector<vector<int>>> data(m, vector<vector<int>>(n, vector<int>(1 << k2p.size(), -1)));
q.emplace(sx,sy,0);
data[sx][sy][0] = 0;
while(!q.empty()){
auto [x,y,curs] = q.front();
q.pop();
for(int pos = 0 ; pos<4 ; pos++){
int cx = x+direction[pos][0];
int cy = y+direction[pos][1];
if(cx>=0&&cx<m&&cy>=0&&cy<n&&grid[cx][cy]!='#'){
if(grid[cx][cy]=='.'||grid[cx][cy]=='@'){
if(data[cx][cy][curs]==-1){
data[cx][cy][curs] = data[x][y][curs]+1;
q.emplace(cx,cy,curs);
}
}
else if(islower(grid[cx][cy])){
int idx = (1<<k2p[grid[cx][cy]]);
if(data[cx][cy][curs|idx]==-1){
data[cx][cy][curs|idx] = data[x][y][curs]+1;
if((curs|idx)==(1<<k2p.size())-1){
return data[cx][cy][curs|idx];
}
q.emplace(cx,cy,curs|idx);
}
}
else{
int idx = (1<<k2p[tolower(grid[cx][cy])]);
if((curs&idx)&&data[cx][cy][curs]==-1){
data[cx][cy][curs] = data[x][y][curs]+1;
q.emplace(cx,cy,curs);
}
}
}
}
}
return -1;
}
};
执行用时:32 ms, 在所有 C++ 提交中击败了50.15%的用户
内存消耗:12.3 MB, 在所有 C++ 提交中击败了32.93%的用户