首页 > 其他分享 >广度优先搜索

广度优先搜索

时间:2024-01-22 21:33:46浏览次数:19  
标签:单词 优先 String int number queue 搜索 new 广度

目录

1. 简介

BFS 的核心思想应该不难理解的,就是把一些问题抽象成图,从一个点开始,向四周开始扩散。一般来说,我们写 BFS 算法都是用「队列」这种数据结构,每次将一个节点周围的所有节点加入队列。

BFS 相对 DFS 的最主要的区别是:BFS 找到的路径一定是最短的,但代价就是空间复杂度可能比 DFS 大很多。

序号 题目 难度
1 752. 打开转盘锁 中等
2 127. 单词接龙 困难

BFS 框架模板如下:

// 计算从起点 start 到终点 target 的最近距离
int BFS(Node start, Node target) {
    Queue<Node> q; // 核心数据结构
    Set<Node> visited; // 避免走回头路
    
    q.offer(start); // 将起点加入队列
    visited.add(start);

    while (q not empty) {
        int sz = q.size();
        /* 将当前队列中的所有节点向四周扩散 */
        for (int i = 0; i < sz; i++) {
            Node cur = q.poll();
            /* 划重点:这里判断是否到达终点 */
            if (cur is target)
                return step;
            /* 将 cur 的相邻节点加入队列 */
            for (Node x : cur.adj()) {
                if (x not in visited) {
                    q.offer(x);
                    visited.add(x);
                }
            }
        }
    }
    // 如果走到这里,说明在图中没有找到目标节点
}

2. 应用

2.1. Leetcode 752. 打开转盘锁

2.1.1. 题目

752. 打开转盘锁

你有一个带有四个圆形拨轮的转盘锁。每个拨轮都有10个数字: '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' 。每个拨轮可以自由旋转:例如把 '9' 变为 '0','0' 变为 '9' 。每次旋转都只能旋转一个拨轮的一位数字。
锁的初始数字为 '0000' ,一个代表四个拨轮的数字的字符串。
列表 deadends 包含了一组死亡数字,一旦拨轮的数字和列表里的任何一个元素相同,这个锁将会被永久锁定,无法再被旋转。
字符串 target 代表可以解锁的数字,你需要给出解锁需要的最小旋转次数,如果无论如何不能解锁,返回 -1 。

示例 1:

输入:deadends = ["0201","0101","0102","1212","2002"], target = "0202"
输出:6
解释:
可能的移动序列为 "0000" -> "1000" -> "1100" -> "1200" -> "1201" -> "1202" -> "0202"。
注意 "0000" -> "0001" -> "0002" -> "0102" -> "0202" 这样的序列是不能解锁的,
因为当拨动到 "0102" 时这个锁就会被锁定。

2.1.2. 解题思路

使用广度优先搜索的思想,从起点开始枚举邻近的数字组合,枚举过程需要跳过死亡数字和已经访问过的数字,直到找到密码为止。

2.1.3. 代码实现

class Solution {
    private static final String START = "0000";
    private static final int SUCCESS = 0;
    private static final int FAIL = -1;

    public int openLock(String[] deadends, String target) {
        if (target.equals(START)) {
            return SUCCESS;
        }
        Set<String> deadNumbers = new HashSet<>(Arrays.asList(deadends));
        if (deadNumbers.contains(START)) {
            return FAIL;
        }

        Set<String> visit = new HashSet<>();
        Queue<String> queue = new LinkedList<>();
        queue.offer(START);
        visit.add(START);
        int step = 0;
        while (!queue.isEmpty()) {
            int size = queue.size();
            for (int i = 0; i < size; i++) {
                String currentNumber = queue.poll();
                for (String number : nextNumber(currentNumber)) {
                    if (visit.contains(number) || deadNumbers.contains(number)) {
                        continue;
                    }

                    if (target.equals(number)) {
                        return step + 1;
                    }
                    queue.offer(number);
                    visit.add(number);
                }
            }
            step += 1;
        }
        return -1;
    }

    private List<String> nextNumber(String number) {
        List<String> result = new ArrayList<>();
        for (int i = 0; i < number.length(); i++) {
            result.add(numberOperate(number.toCharArray(), i, 1));
            result.add(numberOperate(number.toCharArray(), i, -1));
        }
        return result;
    }

    private String numberOperate(char[] state, int i, int value) {
        int newVal = state[i] - '0' + value;
        if (newVal == 10) {
            state[i] = '0';
        } else if (newVal == -1) {
            state[i] = '9';
        } else {
            state[i] = (char) (newVal + '0');
        }
        return new String(state);
    }
}

2.2. Leetcode 127. 单词接龙

2.2.1. 题目

127. 单词接龙

字典 wordList 中从单词 beginWord 和 endWord 的 转换序列 是一个按下述规格形成的序列 beginWord -> s1 -> s2 -> ... -> sk:
每一对相邻的单词只差一个字母。
对于 1 <= i <= k 时,每个 si 都在 wordList 中。注意, beginWord 不需要在 wordList 中。
sk == endWord
给你两个单词 beginWord 和 endWord 和一个字典 wordList ,返回 从 beginWord 到 endWord 的 最短转换序列 中的 单词数目 。如果不存在这样的转换序列,返回 0 。

示例 1:

输入:beginWord = "hit", endWord = "cog", wordList = ["hot","dot","dog","lot","log","cog"]
输出:5
解释:一个最短转换序列是 "hit" -> "hot" -> "dot" -> "dog" -> "cog", 返回它的长度 5。

2.2.2. 解题思路

这里,我们可以使用广度优先搜索的思路,对于每一个单词,我们都可以通过找到它的邻近单词。

即对于当前单词的每一位,都可以将其替换为 \(a - z\) 范围内的其他字母,这样就找到了当前单词的邻近的单词。

2.2.3. 代码实现

class Solution {
    public int ladderLength(String beginWord, String endWord, List<String> wordList) {
        Set<String> canUseWords = new HashSet<>(wordList);
        Set<String> visit = new HashSet<>();
        Queue<String> queue = new LinkedList<>();

        queue.offer(beginWord);
        visit.add(beginWord);
        int step = 1;
        while (!queue.isEmpty()) {
            int size = queue.size();
            for (int i = 0; i < size; i++) {
                String candidate = queue.poll();
                for (String word : nextWord(candidate)) {
                    if (visit.contains(word) || !canUseWords.contains(word)) {
                        continue;
                    }
                    if (word.equals(endWord)) {
                        return step + 1;
                    }
                    queue.offer(word);
                    visit.add(word);
                }
            }
            step++;
        }
        return 0;
    }

    private List<String> nextWord(String word) {
        List<String> result = new ArrayList<>();
        for (int i = 0; i < word.length(); i++) {
            for (char j = 'a'; j <= 'z'; j++) {
                if (j == word.charAt(i)) {
                    continue;
                }
                char[] status = word.toCharArray();
                status[i] = j;
                result.add(new String(status));
            }
        }
        return result;
    }
}

参考:

标签:单词,优先,String,int,number,queue,搜索,new,广度
From: https://www.cnblogs.com/larry1024/p/17964294

相关文章

  • CF-1399-E2-优先队列
    1399-E2题目大意给定一棵\(n\)个节点的树,边带权,根节点为\(1\)。再给定一个整数\(S\),你可以执行以下操作:选择一条权值为\(w_i\)的边,令\(w_i\rightarrow\lfloor\frac{w_i}{2}\rfloor\)。你可以执行任意次操作,使得\(\sum_{x∈leaves}sum(1,x)\)不大于\(S\),其中\(sum(1,x)\)......
  • 如何查询关键词的KD与搜索量
    随着海外贸易的不断发展,越来越多的小伙伴们从事外贸行业,但是随着面对有限的市场和激烈的竞争,很多从业者往往流量的来源比较单一,那就是付费流量,包括谷歌ads,facebook等一些投流广告。广告的好处是当你付出金钱的时候,很快就可以看到结果,点击、曝光甚至表单、下单等这些信息需要不了几......
  • 二分搜索应用 II
    目录1.题目列表2.应用2.1.Leetcode410.分割数组的最大值2.1.1.题目2.1.2.解题思路2.1.3.代码实现1.题目列表序号题目难度1410.分割数组的最大值困难2.应用2.1.Leetcode410.分割数组的最大值2.1.1.题目410.分割数组的最大值给定一个非负整......
  • Visual Studio实用的搜索、查找、替换技巧
    前言对于.NET开发者而言VisualStudio是我们日常工作中比较常用的开发工具,掌握一些VisualStudio实用的搜索、查找、替换技巧可以帮助我们大大提高工作效率从而避免996。VisualStudio更多实用技巧https://github.com/YSGStudyHards/DotNetGuide代码和功能搜索(Ctrl+T)Ctr......
  • Perplexity AI:给搜索引擎注入了新的生命力
    Ai工具集导航(Ai-321.com)新时代的互联网世界中,搜索引擎被誉为“王冠顶上的明珠”。毕竟,百度和谷歌这两大巨头在两岸三地都享有举足轻重的地位。然而,随着AI大模型的崛起,AI赋能搜索引擎已经成为业界的新潮流。国内市场上,昆仑万维的天工AI搜索成为瞩目的新秀;而在海外,则有AI搜索初创公司......
  • 选择器优先级
    1、简单了解    2、详细了解选择器的优先级(a,b,c) 当鼠标悬浮选择器的时候会出现一组权重  行内样式是指在body里直接定义元素的样式 ......
  • 31_修剪二叉搜索树
    669.修剪二叉搜索树给你二叉搜索树的根节点root,同时给定最小边界low和最大边界high。通过修剪二叉搜索树,使得所有节点的值在[low,high]中。修剪树不应该改变保留在树中的元素的相对结构(即,如果没有被移除,原有的父代子代关系都应当保留)。可以证明,存在唯一的答案。所......
  • 30_删除二叉搜索树中的节点
    450.删除二叉搜索树中的节点给定一个二叉搜索树的根节点root和一个值key,删除二叉搜索树中的key对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。一般来说,删除节点可分为两个步骤:首先找到需要删除的节点;如果找到了,删除它。示例1:......
  • 搜索习题汇总
    搜索习题汇总1.[USACO1.4][IOI1994]时钟TheClocks题目描述考虑将如此安排在一个\(3\times3\)行列中的九个时钟:|-------||-------||-------|||||||||---o||---o||o||||||||-------......
  • 百度搜索Push个性化:新的突破
    作者|通用搜索产品研发组导读本文简单介绍了百度搜索Push个性化的发展过程,揭示了面临的困境和挑战:如何筛选优质物料、如何对用户精准推荐等。我们实施了一系列策略方法进行突破,提出核心的解决思路和切实可行的落地方案。提升了搜索DAU和点击率,希望本文的内容能为相关从业者带来启......