【BFS专题】— 解决最短路问题

1、迷宫中离入口最近的出口 - 力扣(LeetCode)

思路:

  1. 利用BFS层序遍历,新建一个变量统计步数
  2. 代码:
    class Solution {
        int dx[] = {0, 0, -1, 1};
        int dy[] = {1, -1, 0, 0};
        public int nearestExit(char[][] maze, int[] entrance) {
            int m = maze.length;
            int n = maze[0].length;
            boolean[][] vis = new boolean[m][n];
            Queue<int[]> q = new LinkedList<>();
            q.offer(new int[]{entrance[0], entrance[1]});
            vis[entrance[0]][entrance[1]] = true;
            int step = 0;
            while(!q.isEmpty()){
                step++;
                int sz = q.size();
                for(int i = 0; i < sz; i++){
                    int[] t = q.poll();
                    int a = t[0];
                    int b = t[1];
                    for(int j = 0; j < 4; j++){
                        int x = a + dx[j];
                        int y = b + dy[j];
                        if(x >= 0 && x < m && y >= 0 && y < n && maze[x][y] == '.' && !vis[x][y]){
                            //判断是否已经走到出口
                            if(x == 0 || x == m - 1 || y == 0 || y == n - 1){
                                return step;
                            }
                            q.add(new int[]{x,y});
                            vis[x][y] = true;
                        }
                    }
                }
            }
            return -1;
        }
    }

 2、最小基因变化 - 力扣(LeetCode)

思路:

  1. 用哈希表来标记搜索过的状态
  2. 遍历原字符串每一位,改成ACGT,再判断是否合法和是否已经出现过
  3. 利用哈希表判断是否在基因库中
  4. 代码:
    class Solution {
        public int minMutation(String startGene, String endGene, String[] bank) {
            //用来标记已经搜索过的状态
            Set<String> vis = new HashSet<>();
            //用来统计基因库中的字符串便于判断
            Set<String> hash = new HashSet<>();
            for(String x : bank){
                hash.add(x);
            }
            char[] change = {'A', 'C', 'G', 'T'};
    
            //如果初识和最终相等就直接返回
            if(startGene.equals(endGene)){
                return 0;
            }
            //如果最终的字符串不存在基因库中就返回-1
            if(!hash.contains(endGene)){
                return -1;
            }
    
            Queue<String> q = new LinkedList<>();
            q.add(startGene);
            vis.add(startGene);
            int step = 0;
            while(!q.isEmpty()){
                step++;
                int sz = q.size();
                //队列的长度
                while(sz-- != 0){
                    String t = q.poll();
                    for(int i = 0; i < 8; i++){
                        char[] tmp = t.toCharArray();
                        for(int j = 0; j < 4; j++){
                            tmp[i] = change[j];
                            String next = new String(tmp);
                            //符合在基因库且没有出现过
                            if(hash.contains(next) && !vis.contains(next)){
                                //判断如果和最终相等就直接返回步数
                                if(next.equals(endGene)){
                                    return step;
                                }
                                q.add(next);
                                vis.add(next);
                            }
                        }
                    }
                }
                
            }
            return -1;
        }
    }

 3、单词接龙 - 力扣(LeetCode)

思路:

  1. 与上一题的思路一样,这道题的范围是‘a’ ~ ‘z’
  2. 返回的长度就是在步数加一
  3. 代码:
    class Solution {
        public int ladderLength(String beginWord, String endWord, List<String> wordList) {
            Set<String> vis = new HashSet<>();
            Set<String> hash = new HashSet<>();
            for(String x : wordList){
                hash.add(x);
            }
            if(beginWord.equals(endWord)){
                return 0;
            }
            if(!hash.contains(endWord)){
                return 0;
            }
            Queue<String> q = new LinkedList<>();
            q.offer(beginWord);
            vis.add(beginWord);
            int len = 0;
            while(!q.isEmpty()){
                len++;
                int sz = q.size();
                while(sz-- != 0){
                    String t = q.poll();
                    for(int i = 0; i < beginWord.length(); i++){
                        char[] tmp = t.toCharArray();
                        for(char ch = 'a'; ch <= 'z'; ch++){
                            tmp[i] = ch;
                            String next = new String(tmp);
                            if(hash.contains(next) && !vis.contains(next)){
                                if(endWord.equals(next)){
                                    return len+1;
                                }
                                q.offer(next);
                                vis.add(next);
                            }
                        }
                    }
                }
            }
            return 0;
        }
    }

 4、为高尔夫比赛砍树 - 力扣(LeetCode)

思路:

  1. 按照树的由低到高来砍树,可以转换成数字低到高的最短路径之和
  2. 先将所以值排序,按照从小到大的最短路径遍历
  3. 代码:
    class Solution {
        int m, n;
        public int cutOffTree(List<List<Integer>> f) {
            m = f.size();
            n = f.get(0).size();
            //1、准备工作确定砍树的顺序
            List<int[]> trees = new ArrayList<>();
            for(int i = 0; i < m; i++){
                for(int j = 0; j < n; j++){
                    if(f.get(i).get(j) > 1){
                        trees.add(new int[]{i, j});
                    }
                }
            }
            //排序
            Collections.sort(trees, (a,b) ->{
                return f.get(a[0]).get(a[1]) - f.get(b[0]).get(b[1]);
            });
    
            //2、按照顺序砍树
            int ret = 0;
            int bx = 0, by = 0;
            for(int[] tree : trees){
                int x = tree[0];
                int y = tree[1];
                int step = bfs(f, bx, by, x, y);
                if(step == -1){
                    return -1;
                }
                ret += step;
                bx = x;
                by = y;
            }
            return ret;
        }
    
        int[] dx = {0, 0, -1, 1};
        int[] dy = {-1, 1, 0, 0};
        public int bfs(List<List<Integer>> f, int bx, int by, int ex, int ey){
            if(bx == ex && by == ey){
                return 0;
            }
            Queue<int[]> q = new LinkedList<>();
            boolean[][] vis = new boolean[m][n];
            q.add(new int[]{bx, by});
            vis[bx][by] = true;
            int step = 0;
            while(!q.isEmpty()){
                step++;
                int sz = q.size();
                while(sz-- != 0){
                    int[] t = q.poll();
                    int a = t[0];
                    int b = t[1];
                    for(int i = 0; i < 4; i++){
                        int x = a + dx[i];
                        int y = b + dy[i];
                        if(x >= 0 && x < m && y >= 0 && y < n && f.get(x).get(y) != 0 && !vis[x][y]){
                            if(x == ex && y == ey ){
                                return step;
                            }
                            q.add(new int[]{x,y});
                            vis[x][y] = true;
                        }
                    }
                }
            }
            return -1;
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值