[leetcode刷题]——搜索

时间:2021-07-13
本文章向大家介绍[leetcode刷题]——搜索,主要包括[leetcode刷题]——搜索使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

  此博客主要记录力扣中关于搜索的题解,包括 BFS、DFS、Backtracking

BFS 

一、计算在网格中从原点到特定点的最短路径长度

1091. 二进制矩阵中的最短路径 (medium) 2021-07-12

给你一个 n x n 的二进制矩阵 grid 中,返回矩阵中最短 畅通路径 的长度。如果不存在这样的路径,返回 -1 。

二进制矩阵中的 畅通路径 是一条从 左上角 单元格(即,(0, 0))到 右下角 单元格(即,(n - 1, n - 1))的路径,该路径同时满足下述要求:

路径途经的所有单元格都的值都是 0 。
路径中所有相邻的单元格应当在 8 个方向之一 上连通(即,相邻两单元之间彼此不同且共享一条边或者一个角)。
畅通路径的长度 是该路径途经的单元格总数。

  经典BFS 题目。

class Solution {
    public int shortestPathBinaryMatrix(int[][] grid) {
        if(grid == null || grid.length == 0 || grid[0].length == 0){
            return -1;
        }
        if(grid[0][0] == 1) return -1;
        int[][] dir = {{1,1}, {1, 0}, {1, -1}, {0, 1}, {0, -1}, {-1, 1}, {-1, 0}, {-1, -1}};
        int m = grid.length;
        int n = grid[0].length;
        Queue<int[]> queue = new LinkedList<>();
        queue.add(new int[]{0, 0});
        grid[0][0] = 1;  //遍历一个节点就置 1 ,记为堵塞
        int path = 1;   //第一层
        while(!queue.isEmpty()){
            int size = queue.size();
            while(size > 0){
                int[] cur = queue.poll();
                int x = cur[0];
                int y = cur[1];
                //结束遍历,返回层数
                if(x == m - 1 && y == n - 1){
                    return path;
                }
                
                for(int[] d : dir){
                    int x1 = x + d[0];
                    int y1 = y + d[1];
                    if(x1 < 0 || x1 >= m || y1 >= m || y1 < 0 || grid[x1][y1] == 1){
                        continue;
                    }
                    queue.add(new int[]{x1, y1});
                    grid[x1][y1] = 1;
                }
                size--;
            }
            path++;
        }
        return -1;
    }
}

二、组成整数的最小平方数数量

279. 完全平方数  (medium) 2021-07-12

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

给你一个整数 n ,返回和为 n 的完全平方数的 最少数量 。

完全平方数 是一个整数,其值等于另一个整数的平方;换句话说,其值等于一个整数自乘的积。例如,1、4、9 和 16 都是完全平方数,而 3 和 11 不是。

  这个题可以使用 BFS 求解,但不是最优解,此方法时间击败 9% 空间击败 4%

  

class Solution {
    public int numSquares(int n) {
        List<Integer> squares = generateSquare(n);
        Queue<Integer> queue = new LinkedList<>();
        queue.add(n);
        int level = 0;
        while(!queue.isEmpty()){
            int size = queue.size();
            level++;
            while(size-- > 0){
                int cur = queue.poll();
                for(int s : squares){
                    int next = cur - s;
                    if(next < 0) break;
                    if(next == 0) return level;
                    queue.add(next);
                }
            }
        }
        return n;
    }

    //这个函数返回小于 n 的所有完全平方数的和,n >= 1
    //实现方法并没有让两数直接相乘,而是使用数学规律
    public List<Integer> generateSquare(int n){
        List<Integer> list = new ArrayList<>();
        int increment = 1;
        int gap = 2;
        int i = 1;
        while(i <= n){
            list.add(i);
            i = i + increment + gap;
            increment += gap;
        }
        return list;
    }
}

三、 最短单词路径

127. 单词接龙 (hard) 2021-07-12

字典 wordList 中从单词 beginWord 和 endWord 的 转换序列 是一个按下述规格形成的序列:

序列中第一个单词是 beginWord 。
序列中最后一个单词是 endWord 。
每次转换只能改变一个字母。
转换过程中的中间单词必须是字典 wordList 中的单词。
给你两个单词 beginWord 和 endWord 和一个字典 wordList ,找到从 beginWord 到 endWord 的 最短转换序列 中的 单词数目 。如果不存在这样的转换序列,返回 0。

   官方解题方法:先给每个单词标号,给每一个单词分配一个id 。创建一个由单词word 到 id 之间的映射 wordId, 并将beginWord 与 wordList 中所有的单词都加入到这个映射中。检查endWord是否在该映射内,如果不存在则输入无解。

  建图的优化方法,创建虚拟节点。如 hit ,我们创建三个虚拟节点 *it , h*t, hi* ,让单词连接虚拟节点再连接单词。最后将路径长度除以 2 。

  官方答案如下

class Solution {
    Map<String, Integer> wordId = new HashMap<String, Integer>();
    List<List<Integer>> edge = new ArrayList<List<Integer>>();
    int nodeNum = 0;
    public int ladderLength(String beginWord, String endWord, List<String> wordList) {
        for(String word : wordList){
            addEdge(word);
        }
        addEdge(beginWord);
        if(!wordId.containsKey(endWord)){
            return 0;
        }
        int[] dis = new int[nodeNum];
        Arrays.fill(dis, Integer.MAX_VALUE);
        int beginId = wordId.get(beginWord);
        int endId = wordId.get(endWord);
        dis[beginId] = 0;
        
        Queue<Integer> que = new LinkedList<Integer>();
        que.add(beginId);
        while(!que.isEmpty()){
            int x = que.poll();
            if(x == endId){
                return dis[endId] / 2 + 1;
            }
            for(int it : edge.get(x)){
                if(dis[it] == Integer.MAX_VALUE){
                    dis[it] = dis[x] + 1;
                    que.add(it);
                }
            }
        }
        return 0;

    }
    public void addEdge(String word){
        addWord(word);
        int id1 = wordId.get(word);
        char[] array = word.toCharArray();
        int length = array.length;
        for(int i = 0; i < length; i++){
            char tmp = array[i];
            array[i] = '*';
            String newWord = new String(array);
            addWord(newWord);
            int id2 = wordId.get(newWord);
            edge.get(id1).add(id2);
            edge.get(id2).add(id1);
            array[i] = tmp;
        }
    }
    
    public void addWord(String word){
        if(!wordId.containsKey(word)){
            wordId.put(word, nodeNum++);
            edge.add(new ArrayList<Integer>());
        }
    }
   
}

   

原文地址:https://www.cnblogs.com/nobita/p/15005361.html