给定一个二维网格 grid。 "." 代表一个空房间, "#" 代表一堵墙, "@" 是起点,("a", "b", ...)代表钥匙,("A", "B", ...)代表锁。
我们从起点开始出发,一次移动是指向四个基本方向之一行走一个单位空间。我们不能在网格外面行走,也无法穿过一堵墙。如果途经一个钥匙,我们就把它捡起来。除非我们手里有对应的钥匙,否则无法通过锁。
假设 K 为钥匙/锁的个数,且满足 1 <= K <= 6,字母表中的前 K 个字母在网格中都有自己对应的一个小写和一个大写字母。换言之,每个锁有唯一对应的钥匙,每个钥匙也有唯一对应的锁。另外,代表钥匙和锁的字母互为大小写并按字母顺序排列。
返回获取所有钥匙所需要的移动的最少次数。如果无法获取所有钥匙,返回 -1 。
示例 1:
输入:["@.a.#","###.#","b.A.B"]
输出:8
示例 2:
输入:["@..aA","..B#.","....b"]
输出:6
提示:
1 <= grid.length <= 30
1 <= grid[0].length <= 30
grid[i][j] 只含有 '.', '#', '@', 'a'-'f' 以及 'A'-'F'
钥匙的数目范围是 [1, 6],每个钥匙都对应一个不同的字母,正好打开一个对应的锁。
思路:一道没有任何难点和坑点的题,就是比较烦。我的方法是求出取钥匙顺序的全排列,然后按照每种排列顺序取钥匙,从中找到最小值。
class Solution {
private int ans;
List<Character> alplist;
private List<List<Integer>> list;
private int[] dx= {1,-1,0,0};
private int[] dy= {0,0,1,-1};
private char[][] map;
private boolean[] mark;
public int shortestPathAllKeys(String[] grid) {
ans=Integer.MAX_VALUE;
mark=new boolean[6];
int m=grid.length;
int n=grid[0].length();
map=new char[m][n];
list=new ArrayList<>();
alplist=new ArrayList<>();
for(int i=0;i<m;i++)
map[i]=grid[i].toCharArray();
int stx=0,sty=0;
for(int i=0;i<m;i++)
for(int j=0;j<n;j++) {
if(map[i][j]=='@') { stx=i; sty=j; }
if(map[i][j]>='a' && map[i][j]<='f') alplist.add(map[i][j]);
}
permutation(new ArrayList<>());
for(int i=0;i<list.size();i++)
ans=Math.min(ans, bfs(stx,sty,i));
return ans==Integer.MAX_VALUE?-1:ans;
}
private int bfs(int x,int y,int index) {
int res=0;
List<Integer> nowList=list.get(index);
Map<Character,Boolean> used=new HashMap<>();
boolean[][] flag=new boolean[map.length][map[0].length];
int lastx=x,lasty=y;
for(int i=0;i<nowList.size();i++) {
int sum=-1;
Queue<int[]> q=new LinkedList<>();
q.add(new int[] {lastx,lasty,0});
flag[lastx][lasty]=true;
while(!q.isEmpty()) {
int[] now=q.poll();
if(now[2]>ans) return Integer.MAX_VALUE; //一个小小的剪枝
if(map[now[0]][now[1]]==alplist.get(nowList.get(i))) {
lastx=now[0]; lasty=now[1];
used.put(Character.toUpperCase(map[now[0]][now[1]]), true);
sum=now[2];
break;
}
for(int j=0;j<4;j++) {
int xx=now[0]+dx[j];
int yy=now[1]+dy[j];
if(xx<0 || xx>=map.length || yy<0 || yy>=map[0].length
|| flag[xx][yy] || map[xx][yy]=='#')
continue;
if(map[xx][yy]>='A' && map[xx][yy]<='F') {
if(!used.containsKey(map[xx][yy]))
continue;
}
flag[xx][yy]=true;
q.add(new int[] {xx,yy,now[2]+1});
}
}
if(sum==-1) return Integer.MAX_VALUE;
else res+=sum;
for(int k=0;k<map.length;k++)
for(int h=0;h<map[0].length;h++)
flag[k][h]=false;
}
return res;
}
private void permutation(List<Integer> now) {
if(now.size()==alplist.size()) {
list.add(new ArrayList<>(now));
return;
}
for(int i=0;i<alplist.size();i++) {
if(mark[i]) continue;
mark[i]=true;
now.add(i);
permutation(now);
now.remove(now.size()-1);
mark[i]=false;
}
}
}