• leetcode系列之 BFS


    写在前面:该系列按照标签进行刷题,参考 leetcode标签

    广度优先搜索 BFS

    1091.二进制矩阵中的最短路径

    在一个 N × N 的方形网格中,每个单元格有两种状态:空(0)或者阻塞(1)。

    一条从左上角到右下角、长度为 k 的畅通路径,由满足下述条件的单元格 C_1, C_2, ..., C_k 组成:

    • 相邻单元格 C_iC_{i+1} 在八个方向之一上连通(此时,C_iC_{i+1} 不同且共享边或角)

    • C_1 位于 (0, 0)(即,值为 grid[0][0]

    • C_k 位于 (N-1, N-1)(即,值为 grid[N-1][N-1]

    • 如果 C_i 位于 (r, c),则 grid[r][c] 为空(即,grid[r][c] == 0

    返回这条从左上角到右下角的最短畅通路径的长度。如果不存在这样的路径,返回 -1 。

    看到最短路径,可以考虑 BFS,利用 grid 表达当前点的路径。


    BFS:

    class Solution {
        private int[][] dist={{-1,-1},{-1,0},{-1,1},{0,-1},{0,1},{1,-1},{1,0},{1,1}};
        public int shortestPathBinaryMatrix(int[][] grid) {
            // 10:03
            // 从左上角到右下角,多种路径选择其中一条
            int rows=grid.length;
            int cols=grid[0].length;
            if(grid[0][0]==1 || grid[rows-1][cols-1]==1) return -1;
            Queue<int []> queue=new LinkedList<>();
            int fir[]={0,0};//起点
            grid[0][0]=1;//利用 grid 记录距离
            queue.offer(fir);
            // grid[rows-1][cols-1]==0 代表还没有走到终点
            while(!queue.isEmpty() && grid[rows-1][cols-1]==0){
                int temp[]=queue.poll();
                int row=temp[0];
                int col=temp[1];
                for(int i=0;i<8;i++){
                    int newx=row+dist[i][0];
                    int newy=col+dist[i][1];
                    if(newx <0 || newx>=rows || newy <0|| newy >=cols) continue;
                    if(grid[newx][newy]==0){//判断新点是否已经到达
                        grid[newx][newy]=grid[row][col]+1;
                        queue.offer(new int[]{newx,newy});
                    }
                }
            }
            // 若最后末尾点为0,证明没有路径可以到达,否则返回末尾点的值即路径
            return grid[rows-1][cols-1]==0 ? -1:grid[rows-1][cols-1];
        }
    }
    

    279.完全平方数

    给定正整数 n,找到若干个完全平方数(比如 1, 4, 9, 16, ...)使得它们的和等于 n。你需要让组成和的完全平方数的个数最少。

    //示例 1:
    
    输入: n = 12
    输出: 3 
    解释: 12 = 4 + 4 + 4.
    //示例 2:
    
    输入: n = 13
    输出: 2
    解释: 13 = 4 + 9.
    

    BFS:相当于构建一个树。第一层是n,第二层是n减去每个完全平方数的结果,第三层是第二层减之后的结果,哪一层先出现0,层数即个数。

    动态规划:状态转移方程:dp[i]=min(dp[i],dp[i-j*j]+1),类似硬币问题。


    1.BFS:

    class Solution {
        public int numSquares(int n) {
            // 10:44
            // 1 4 9 16 25
            List<Integer> squares=square(n);
            Queue<Integer> queue=new LinkedList<>();
            boolean flag[]=new boolean[n+1];
            queue.offer(n);
            flag[n]=true;
            int num=0;
            // 对n减完全平方数,当结果为0时即所需个数
            while(!queue.isEmpty()){
                int size=queue.size();
                num++;
                while(size-- >0){
                    int cur=queue.poll();
                    for(int s:squares){
                        int res=cur-s;
                        if(res==0) return num;
                        if(res<0) break;
                        if(flag[res]) continue;//若结果值已访问则进行下一次遍历
                        flag[res]=true;
                        queue.offer(res);
                    }
                }
            }
            return num;
        }
        //生成小于n的完全平方数列表
        public List<Integer> square(int n){
            List<Integer> res=new ArrayList<>();
            int square=1;
            int count=1;
            while(square<=n){
                res.add(square);
                count++;
                square=count*count;
            }
            return res;
        }
    }
    

    2.动态规划

    class Solution {
        public int numSquares(int n) {
            // 10:44
            // DP :状态转移方程:dp[i]=min(dp[i],dp[i-j*j]+1);
            if(n<1) return 0;
            int[] dp=new int[n+1];
            for(int i=1;i<n+1;i++){
                dp[i]=i;//最坏情况,全部由1组成
                for(int j=1;i-j*j>=0;j++){
                    dp[i]=Math.min(dp[i],dp[i-j*j]+1);
                }
            }
            return dp[n];
        }
    
    }
    

    127.单词接龙

    给定两个单词(beginWord 和 endWord)和一个字典,找到从 beginWord 到 endWord 的最短转换序列的长度。转换需遵循如下规则:

    • 每次转换只能改变一个字母。

    • 转换过程中的中间单词必须是字典中的单词。

    说明:

    • 如果不存在这样的转换序列,返回 0。
    • 所有单词具有相同的长度。
    • 所有单词只由小写字母组成。
    • 字典中不存在重复的单词。
    • 你可以假设 beginWord 和 endWord 是非空的,且二者不相同。
    //示例 1:
    输入:
    beginWord = "hit",
    endWord = "cog",
    wordList = ["hot","dot","dog","lot","log","cog"]
    
    输出: 5
    
    解释: 一个最短转换序列是 "hit" -> "hot" -> "dot" -> "dog" -> "cog",
         返回它的长度 5。
    
    //示例 2:
    输入:
    beginWord = "hit"
    endWord = "cog"
    wordList = ["hot","dot","dog","lot","log"]
    
    输出: 0
    
    解释: endWord "cog" 不在字典中,所以无法进行转换。
    

    BFS:重点是找到只差一个单词的字符串,然后每次遍历一个字符串,找寻和它相差一个的字符串,判断是否是目标字符串。


    1.BFS:

    class Solution {
      public int ladderLength(String beginWord, String endWord, List<String> wordList) {
        // 11:35
    
        int L = beginWord.length();
        // 存储通用字符和字典中与其对应的字符串列表:d*g->{dog,dig}
        Map<String, List<String>> allComboDict = new HashMap<>();
    
        wordList.forEach(
            word -> {
              for (int i = 0; i < L; i++) {
                String newWord = word.substring(0, i) + '*' + word.substring(i + 1, L);
                // 找到字典中通用字符对应的字符列表,若为空则创建一个新列表
                List<String> transformations = allComboDict.getOrDefault(newWord, new ArrayList<>());
                transformations.add(word);
                allComboDict.put(newWord, transformations);
              }
            });
    
        // pair 存储字符串与转换到该字符串所需的次数
        Queue<Pair<String, Integer>> Q = new LinkedList<>();
        Q.add(new Pair(beginWord, 1));
    
        // 访问标志
        Map<String, Boolean> visited = new HashMap<>();
        visited.put(beginWord, true);
        // BFS
        while (!Q.isEmpty()) {
          Pair<String, Integer> node = Q.remove();
          String word = node.getKey();
          int level = node.getValue();
          for (int i = 0; i < L; i++) {
    
            //当前字符串的通用字符形式
            String newWord = word.substring(0, i) + '*' + word.substring(i + 1, L);
    
            // 从map中获得字典中该通用字符对应的字符串列表
            for (String adjacentWord : allComboDict.getOrDefault(newWord, new ArrayList<>())) {
              //如果找到字符串对应目标字符串,则返回层数+1
              if (adjacentWord.equals(endWord)) {
                return level + 1;
              }
              // 如果不等则判断是否已访问,未访问则置为访问,同时加入队列
              if (!visited.containsKey(adjacentWord)) {
                visited.put(adjacentWord, true);
                Q.add(new Pair(adjacentWord, level + 1));
              }
            }
          }
        }
    
        return 0;
      }
    }
    
  • 相关阅读:
    模块模式——属性
    防止变量被覆盖
    自执行匿名函数语法和普通函数语法对比
    JavaScript更改原型
    JavaScript覆盖原型以及更改原型
    JavaScript原型链
    作用域链和原型链描述javaScript访问变量和属性的顺序
    javascript高级变量提升和执行环境对象
    构建第一个单页应用
    error: expected identifier before numeric constant 问题
  • 原文地址:https://www.cnblogs.com/lfz1211/p/12893392.html
Copyright © 2020-2023  润新知