JAVA程序设计:获取所有钥匙的最短路径(LeetCode:864)

给定一个二维网格 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;
    	}
    }
}
原创文章 1111 获赞 194 访问量 25万+

猜你喜欢

转载自blog.csdn.net/haut_ykc/article/details/105679150