对应 LeetCode 127 单词接龙

问题定义

给定一个字典序列 wordList,一个初始的单词 beginWord 和一个目标单词 endWord,现在要求每次变换满足以下条件将 beginWord 转换为 endWord

  • 每次只能转换一个字母
  • 转换后的单词必须出现在 wordList

求是否能够在满足对应的转换条件的前提下,能否将 beginWord 转换成 endWord,如果可以转换,则返回转换的最少次数;如果不能转换,则返回 0

数据范围:

  • \(1 <= beginWord.length <= 10\)
  • \(endWord.length == beginWord.length\)
  • \(1 <= wordList.length <= 5000\)
  • \(wordList[i].length == beginWord.length\)
  • \(beginWord\)、\(endWord\) 和 \(wordList[i]\) 由小写英文字母组成
  • \(beginWord != endWord\)

解决思路

  • BFS

    这个问题是一个典型的 BFS 问题,只需要每次遍历时对每个单词的每个位置进行相应的转换,再进行比较即可,使用一个 Map 来记录当前的操作次数

  • 双向 BFS

    由于数据量比较大,使用一般的 BFS 的搜索方式使得导致每次的维度的节点数量爆炸式的增长,根据题意,最终的 end 需要在 wordList 中才有可能能进行转换,因此可以从 beginWordendWord 两个方向出发,使得搜索的节点数大幅度减少,从而减少计算时间

  • A* 搜索

    每个转换的单词之间的相差的字母的数量可以看成是一个带有权重的边,此时这个问题就可以转换成为一般的图搜索问题,即找到一条权重最小的路径从 beinWord ——> endWord

实现

  • BFS

    class Solution {
    public int ladderLength(String beginWord, String endWord, List<String> wordList) {
    if (!wordList.contains(endWord)) return 0; Deque<String> deque = new LinkedList<>();
    Map<String, Integer> map = new HashMap<>(); // 用于记录已经访问的路径长度 deque.offer(beginWord);
    map.put(beginWord, 1); while (!deque.isEmpty()) {
    int size = deque.size(); // 每层需要遍历的节点的数量
    while (size-- > 0) {
    String node = deque.poll();
    int n = node.length();
    char[] array = node.toCharArray();
    // 转换部分。。
    for (int i = 0; i < n; ++i) {
    char ch = array[i];
    for (int j = 0; j < 26; ++j) {
    array[i] = (char) ('a' + j);
    String sub = String.valueOf(array); if (!wordList.contains(sub)) continue;
    if (map.containsKey(sub)) continue; if (sub.equals(endWord))
    return map.get(node) + 1; map.put(sub, map.get(node) + 1);
    deque.offer(sub);
    } array[i] = ch;
    }
    }
    } return 0;
    }
    }

    直接使用 BFS 的方式会导致访问的节点数量爆炸性地增长,因此这种方式会导致超时

  • 双向 BFS

    class Solution {
    private final Set<String> set = new HashSet<>(); public int ladderLength(String begin, String end, List<String> wordList) {
    if (!wordList.contains(end)) return 0; set.addAll(wordList); int ans = bfs(begin, end); return ans == -1 ? 0 : ans + 1;
    } int bfs(String begin, String end) {
    Deque<String> cur = new LinkedList<>();
    Deque<String> other = new LinkedList<>(); // 从 beiginWord 向下搜索
    Map<String, Integer> top = new HashMap<>();
    // 从 endWord 向上搜素
    Map<String, Integer> bottom = new HashMap<>(); top.put(begin, 0);
    bottom.put(end, 0); cur.offer(begin);
    other.offer(end); while (!cur.isEmpty() && !other.isEmpty()) {
    int t = -1;
    // 交替搜索,使得每次遍历的节点数是平衡的
    if (cur.size() <= other.size()) {
    t = update(cur, top, bottom);
    } else {
    t = update(other, bottom, top);
    } if (t != -1) return t;
    } return -1;
    } int update(
    Deque<String> d,
    Map<String, Integer> top,
    Map<String, Integer> bottom
    ) {
    String node = d.poll();
    int val = top.get(node); int n = node.length(); // 转换每个位置的字母,搜索满足条件的单词
    char[] array = node.toCharArray();
    for (int i = 0; i < n; ++i) {
    char ch = array[i];
    for (int j = 0; j < 26; ++j) {
    array[i] = (char) ('a' + j);
    String tmp = String.valueOf(array); if (!set.contains(tmp)) continue;
    if (top.containsKey(tmp)) continue; if (bottom.containsKey(tmp))
    return val + bottom.get(tmp) + 1; d.offer(tmp);
    top.put(tmp, val + 1);
    }
    array[i] = ch;
    } return -1;
    }
    }
  • A* 搜索

    class Solution {
    static class Node {
    String str;
    int val; Node(String _str, int _val) {
    this.str= _str;
    this.val = _val;
    }
    } String s, e;
    int INF = 0x3f3f3f3f;
    Set<String> set = new HashSet<>(); public int ladderLength(String _s, String _e, List<String> wordList) {
    this.s = _s;
    this.e = _e; this.set.addAll(wordList); int ans = aStar(); return ans == -1 ? 0 : ans + 1;
    } int aStar() {
    PriorityQueue<Node> pq = new PriorityQueue<>((a, b) -> a.val - b.val);
    Map<String, Integer> dist = new HashMap<>();
    dist.put(s, 0);
    pq.offer(new Node(s, find(s))); // 搜索边。。
    while (!pq.isEmpty()) {
    Node node = pq.poll();
    String str = node.str;
    if (str.equals(e)) break; int distance = dist.get(str);
    int n = str.length(); // 字母转换部分
    char[] array = str.toCharArray();
    for (int i = 0; i < n; ++i) {
    char ch = array[i];
    for (int j = 0; j < 26; ++j) {
    array[i] = (char) ('a' + j);
    String sub = String.valueOf(array);
    if (!set.contains(sub)) continue; if (!dist.containsKey(sub) || dist.get(sub) > distance + 1) {
    dist.put(sub, distance + 1);
    pq.offer(new Node(sub, find(sub) + dist.get(sub)));
    }
    } array[i] = ch;
    }
    } return dist.containsKey(e) ? dist.get(e) : -1;
    } int find(String str) {
    if (str.length() != e.length()) return INF;
    int n = str.length();
    int ans = 0; for (int i = 0; i < n; ++i) {
    ans += str.charAt(i) == e.charAt(i) ? 0 : 1;
    } return ans;
    }
    }

参考:

[1] https://leetcode-cn.com/problems/word-ladder/solution/gong-shui-san-xie-ru-he-shi-yong-shuang-magjd/

BFS(一)单词接龙的更多相关文章

  1. 单词接龙(dragon)(BFS)

    单词接龙(dragon) 时间限制: 1 Sec  内存限制: 64 MB提交: 12  解决: 5[提交][状态][讨论版] 题目描述 单 词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已 ...

  2. Leetcode之广度优先搜索(BFS)专题-127. 单词接龙(Word Ladder)

    Leetcode之广度优先搜索(BFS)专题-127. 单词接龙(Word Ladder) BFS入门详解:Leetcode之广度优先搜索(BFS)专题-429. N叉树的层序遍历(N-ary Tre ...

  3. Leetcode 126.单词接龙II

    单词接龙II 给定两个单词(beginWord 和 endWord)和一个字典 wordList,找出所有从 beginWord 到 endWord 的最短转换序列.转换需遵循如下规则: 每次转换只能 ...

  4. LeetCode 126. Word Ladder II 单词接龙 II(C++/Java)

    题目: Given two words (beginWord and endWord), and a dictionary's word list, find all shortest transfo ...

  5. Java实现 LeetCode 127 单词接龙

    127. 单词接龙 给定两个单词(beginWord 和 endWord)和一个字典,找到从 beginWord 到 endWord 的最短转换序列的长度.转换需遵循如下规则: 每次转换只能改变一个字 ...

  6. Java实现 LeetCode 126 单词接龙 II

    126. 单词接龙 II 给定两个单词(beginWord 和 endWord)和一个字典 wordList,找出所有从 beginWord 到 endWord 的最短转换序列.转换需遵循如下规则: ...

  7. NOIP2000单词接龙[DFS]

    题目描述 单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的“龙”(每个单词都最多在“龙”中出现两次),在两个单词相连时,其重合 ...

  8. Noip2000 T3 单词接龙

    题目描述 单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的“龙”(每个单词都最多在“龙”中出现两次),在两个单词相连时,其重合 ...

  9. 洛谷 P1019 单词接龙 Label:dfs

    题目描述 单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的“龙”(每个单词都最多在“龙”中出现两次),在两个单词相连时,其重合 ...

  10. 【wikioi】1018 单词接龙

    题目链接 算法:DFS+考你阅题 题目描述: 单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的“龙”(每个单词都最多在“龙”中 ...

随机推荐

  1. TTS背后的技术原理——前端和后端系统

        就解锁了一个温柔又风趣的「女朋友」萨曼萨.不过,在现实生活中,和语音助手谈恋爱还是一件十分遥远的事情--刨去现阶段的语音助手们双商水平还有限,语音助手的语言表达能力还远远达不到我们理想状态. ...

  2. PPT太大发不出去?教你三个PPT压缩方法,200M的PPT变15M

    相信有很多小伙伴在工作的时候,都会制作不少的PPT,而我们也知道很多PPT在制作完成以后,体积就会变得非常大,在发送给别人的时候总是会受到限制,是有点难搞了. 别担心,今天小编将告诉大家三个简单的方法 ...

  3. C#堆排序算法

    前言 堆排序是一种高效的排序算法,基于二叉堆数据结构实现.它具有稳定性.时间复杂度为O(nlogn)和空间复杂度为O(1)的特点. 堆排序实现原理 构建最大堆:将待排序数组构建成一个最大堆,即满足父节 ...

  4. CSS 还原拉斯维加斯球数字动画

    我的小册 <CSS 技术揭秘与实战通关>上线了,想了解更多有趣.进阶.系统化的 CSS 内容,可以猛击 - LINK. 最近大家刷抖音,是否有刷到拉斯维加斯的新地标 「Sphere」: 场 ...

  5. Go语言代码断行规则详解

    本文深入探讨了Go语言中代码断行的各个方面,从基础概念到实际应用实践. 关注[TechLeadCloud],分享互联网架构.云服务技术的全维度知识.作者拥有10+年互联网服务架构.AI产品研发经验.团 ...

  6. DS必背合集

    Data Structure必背合集 一.链表.栈和队列 1.简述说明数据的存储结构: 答: (1)顺序存储:逻辑上相邻的两个元素的物理位置也相邻. 优点:能够随机存取. 缺点:插入删除需要移动大量的 ...

  7. JavaScript 语法:数组的定义及其常用属性与方法

    作者:WangMin 格言:努力做好自己喜欢的每一件事 当一个程序需要用到多个数据的时候,这时我们就需要用到数组来将这些数据集合起来,以便后期调用.接下来就开始学习吧!! 数组的定义方法 1 .第一种 ...

  8. 【re】[NISACTF 2022]string --linux下的随机数

    附件下载,查壳 发现是ELF程序,64位,ida打开分析 flag函数点进去 前面一堆代码其实都不重要,直接看主要代码:  puts("The length of flag is 13&qu ...

  9. 《流畅的Python》 读书笔记 第8章_对象引用、可变性和垃圾回收

    第8章_对象引用.可变性和垃圾回收 本章的主题是对象与对象名称之间的区别.名称不是对象,而是单独的东西 name = 'wuxianfeng' # name是对象名称 'wuxianfeng'是个st ...

  10. UVA529 加成序列

    传送门 题目分析 一道 dfs,迭代加深 我们可以很快的猜出来最终 \(m\) 的长度必然是小于 \(10\) 的. 而这种浅深度的问题正好适用于迭代加深. 之后考虑剪枝 优化搜索顺序 : 我们要让序 ...