leetcode 864. 获取所有钥匙的最短路径 BFS+位运算

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Viscu/article/details/82505604

给定一个二维网格 grid。 “.” 代表一个空房间, “#” 代表一堵墙, “@” 是起点,(”a”, “b”, …)代表钥匙,(”A”, “B”, …)代表锁。
我们从起点开始出发,一次移动是指向四个基本方向之一行走一个单位空间。我们不能在网格外面行走,也无法穿过一堵墙。如果途经一个钥匙,我们就把它捡起来。除非我们手里有对应的钥匙,否则无法通过锁。
假设 K 为钥匙/锁的个数,且满足 1 <= K <= 6,字母表中的前 K 个字母在网格中都有自己对应的一个小写和一个大写字母。换言之,每个锁有唯一对应的钥匙,每个钥匙也有唯一对应的锁。另外,代表钥匙和锁的字母互为大小写并按字母顺序排列。
返回获取所有钥匙所需要的移动的最少次数。如果无法获取所有钥匙,返回 -1 。

思路:看代码+解释 运用位运算来简化代码 简单题 多了一维存储钥匙的状态而已。
class Solution {
    int[] dx={0,0,1,-1}; //上下左右移动
    int[] dy={1,-1,0,0};
    boolean[][][] vis; //前两位表示左边,后一位表示当前拥有钥匙的状态
    static class Idx{
        int x;  
        int y;
        int cnt;  //表示当前的步数
        int keyState;  //表示当前有用钥匙的状态  
        //怎么表示,因为有6把钥匙 所以我们用6位bit表示当前拥有钥匙的状态 eg: 000101表示当前拥有a,c钥匙  
        public Idx(int x, int y, int cnt, int keyState){
            this.x = x;
            this.y = y;
            this.cnt = cnt;
            this.keyState = keyState;
        }
    }
    public int shortestPathAllKeys(String[] grid) {
        int n=grid.length;
        int m=grid[0].length();
        Idx st=null;
        int sx=0;
        int sy=0;
        int keySum=0;//表示状态
        for(int i=0;i<n;++i){
            for(int j=0;j<m;++j){
                char ch=grid[i].charAt(j);
                if(ch=='@'){ //寻找起点
                    sx=i;
                    sy=j;
                    st=new Idx(i,j,0,0);
                }
                if(ch>='a'&&ch<='f'){
                    keySum|=1<<ch-'a'; //保存钥匙的状态 样例1为000011.
                }
            }
        }
        vis=new boolean[n][m][keySum+1];
        vis[sx][sy][0]=true; //初始位置标志为已经走过
        Queue<Idx> queue=new LinkedList<Idx>();
        queue.add(st);
        while (!queue.isEmpty()){
            Idx cur=queue.poll();
            if(cur.keyState==keySum){  //若当前钥匙状态与之比较相同 说明已经拥有全部的钥匙
                return cur.cnt; //直接返回步数
            }
            for(int i=0;i<4;++i){ //上下左右遍历
                int xi=cur.x+dx[i]; 
                int yi=cur.y+dy[i];
                if(xi<0||yi<0||xi>=n||yi>=m||vis[xi][yi][cur.keyState]
                        ||grid[xi].charAt(yi)=='#'){  //越界或者墙不能走
                    continue;
                }
                int keyState=cur.keyState;
                char ch=grid[xi].charAt(yi);
                if(ch>='a'&&ch<='f'){  //如果是钥匙 保存钥匙
                    keyState|=1<<(ch-'a'); // 遇到a keyState为 000001
                }
                if(ch>='A'&&ch<='F'){ //遇到门
                    int doorState=ch-'A';  // 该位运算的意义就是第几把钥匙是否存在
                    if((keyState>>doorState&1)!=1){  //即第ch-'A'位置上是否为1 为1说明有钥匙 左移处理
                        continue;
                    }
                }
                vis[xi][yi][keyState]=true;  //设置当前为走过 多个状态 后面表示的是所拥有的钥匙的状态
                queue.add(new Idx(xi,yi,cur.cnt+1,keyState));
            }
        }
        return -1;
    }
}

猜你喜欢

转载自blog.csdn.net/Viscu/article/details/82505604