Leetcode127.单词接龙

https://leetcode.cn/problems/word-ladder/description/?envType=study-plan-v2&envId=top-interview-150

文章目录

  • 题目描述
  • 解题思路
  • 代码-BFS
  • 解题思路二——双向BFS
  • 代码

题目描述

字典 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:
输入:beginWord = “hit”, endWord = “cog”, wordList = [“hot”,“dot”,“dog”,“lot”,“log”]
输出:0
解释:endWord “cog” 不在字典中,所以无法进行转换。

提示:

1 <= beginWord.length <= 10
endWord.length == beginWord.length
1 <= wordList.length <= 5000
wordList[i].length == beginWord.length
beginWord、endWord 和 wordList[i] 由小写英文字母组成
beginWord != endWord
wordList 中的所有字符串 互不相同

解题思路

  • 无向图中两个顶点之间的最短路径的长度,可以通过广度优先遍历得到;

  • 为什么 BFS 得到的路径最短?可以把起点和终点所在的路径拉直来看,两点之间线段最短;

  • 已知目标顶点的情况下,可以分别从起点和目标顶点(终点)执行广度优先遍历,直到遍历的部分有交集,这是双向广度优先遍历的思想。

  • 「转换」意即:两个单词对应位置只有一个字符不同,例如 “hit” 与 “hot”,这种转换是可以逆向的,因此,根据题目给出的单词列表,可以构建出一个无向(无权)图;
    在这里插入图片描述

  • 如果一开始就构建图,每一个单词都需要和除它以外的另外的单词进行比较,复杂度是 O(NwordLen),这里 N是单词列表的长度;当单词个数很多的时候,找到邻居的时间复杂度就很高了。

  • 为此,我们在遍历一开始,把所有的单词列表放进一个哈希表中,然后在遍历的时候构建图,每一次得到在单词列表里可以转换的单词,复杂度是 O(26×wordLen),借助哈希表,找到邻居与 N无关;

  • 使用 BFS 进行遍历,需要的辅助数据结构是:

    • 队列;
    • visited 集合。说明:可以直接在 wordSet (由 wordList 放进集合中得到)里做删除。但更好的做法是新开一个哈希表,遍历过的字符串放进哈希表里。这种做法具有普遍意义。绝大多数在线测评系统和应用场景都不会在意空间开销。

代码-BFS

class Solution {public int ladderLength(String beginWord, String endWord, List<String> wordList) {// 单向BFS写法// 第一步现将wordList放到哈希表中,便于判断某个单词是否在wordList中Set<String> wordSet = new HashSet<>(wordList);if(wordSet.size() == 0 || !wordSet.contains(endWord)){return 0;}// 把起点删了,以免节外生枝,不删提交也能过// wordSet.remove(beginWord);// 广度的队列Queue<String> queue = new LinkedList<>();queue.offer(beginWord);// 因为是字符串,所以要标记是否使用要用HashSetSet<String> visited = new HashSet<>();visited.add(beginWord);// 开始广搜,包含起点,因此初始化的步数为1int step = 1;while(!queue.isEmpty()){int currentSize = queue.size();for(int i=0; i< currentSize; i++){// 依次遍历当前队列中的单词String currentWord = queue.poll();// 尝试变异,修改其中的每一个字符,看看是否能与终态匹配for(int j=0; j<currentWord.length(); j++){char[] originWord = currentWord.toCharArray();char originChar = originWord[j];   // 先保存,再恢复,或者使用originWord.clone(),修改备份for(char k = 'a'; k<= 'z'; k++){if(originChar == k) // 和当前位置相同,跳过continue;originWord[j] = k;  // 尝试修改String nextWord = String.valueOf(originWord); // 还要在换回字符串判断if(wordSet.contains(nextWord)){if(nextWord.equals(endWord)){return step + 1;}if(!visited.contains(nextWord)){queue.offer(nextWord);visited.add(nextWord);  // 注意,添加到队列以后,必须马上标记为已访问}}}originWord[j] = originChar;  // 恢复}}step += 1;}return 0;}
}

解题思路二——双向BFS

  • 已知目标顶点的情况下,可以分别从起点和目标顶点(终点)执行广度优先遍历,直到遍历的部分有交集。这种方式搜索的单词数量会更小一些;
  • 优化一下,每次从单词数量小的集合开始扩散;
  • 这里 beginVisited 和 endVisited 交替使用,等价于单向 BFS 里使用队列,每次扩散都要加到总的 visited 里。
    在这里插入图片描述
    这样可以看出,使用双向BFS遍历的时候,访问的节点个数更少,当两侧的BFS交叉的时候就说明联通了。

代码

class Solution {public int ladderLength(String beginWord, String endWord, List<String> wordList) {// 双向BFS// 第 1 步:先将 wordList 放到哈希表里,便于判断某个单词是否在 wordList 里Set<String> wordSet = new HashSet<>(wordList);if(wordSet.size() == 0 || !wordSet.contains(endWord)){return 0;}// 已经访问过得word,添加到visited哈希表里Set<String> visited = new HashSet<>();//分别用左边和右边扩散的哈希表代替单向 BFS 里的队列,它们在双向 BFS 的过程中交替使用Set<String> beginVisited = new HashSet<>();beginVisited.add(beginWord);Set<String> endVisited = new HashSet<>();endVisited.add(endWord);visited.add(beginWord);visited.add(endWord);// 执行双向BFS,左右交替扩散步数之和为答案int step = 1;while(!beginVisited.isEmpty() && !endVisited.isEmpty()){// 优先选择小的哈希表进行扩散,考虑到的情况更少if(beginVisited.size() > endVisited.size()){Set<String> temp = beginVisited;beginVisited = endVisited;endVisited = temp;}// 逻辑到这里,保证 beginVisited 是相对较小的集合,nextLevelVisited 在扩散完成以后,会成为新的 beginVisitedSet<String> nextLevelVisited = new HashSet<>();for(String word: beginVisited){char[] originWord = word.toCharArray();for(int i=0; i<word.length(); i++){char originChar = originWord[i];for(char k = 'a'; k<='z'; k++){if(originWord[i] == k)continue;originWord[i] = k;String nextWord = String.valueOf(originWord);if(wordSet.contains(nextWord)){if(endVisited.contains(nextWord)){   // 前后的BFS交叉了,说明连上了return step + 1;}if(!visited.contains(nextWord)){nextLevelVisited.add(nextWord);visited.add(nextWord);}}}originWord[i] = originChar;}}// 原来的 beginVisited 废弃,从 nextLevelVisited 开始新的双向 BFSbeginVisited = nextLevelVisited;step++;}return 0;}}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/8705.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2024.05.08作业

登陆部分代码 /登陆槽函数 void Widget::btn_clicked() {if(edit1->text()"Admin" && edit2->text()"123456"){//登陆成功对话框QMessageBox box(QMessageBox::Information,"信息对话框","登陆成功",QMessageBox::Ok,t…

制冷机组喷液冷却与经济器的介绍

在制冷机组中&#xff0c;喷液冷却与经济器两者虽同可以为提升制冷系统效率与性能&#xff0c;经济器是一种特殊的换热器&#xff0c;主要用于制冷系统中&#xff0c;以提高系统的效率和性能。通常安装在制冷机组的冷凝器之后、膨胀阀之前的位置&#xff0c;确保在制冷剂流向蒸…

hadoop学习---基于Hive的教育平台数据仓库分析案例(三)

衔接第一部分&#xff0c;第一部分请点击&#xff1a;基于Hive的教育平台数据仓库分析案例&#xff08;一) 衔接第二部分&#xff0c;第二部分请点击&#xff1a;基于Hive的教育平台数据仓库分析案例&#xff08;二) 学生出勤模块&#xff08;全量分析&#xff09;&#xff1a…

生产制造中刀具管理系统,帮助工厂不再频繁换刀

一、刀具管理的定义与重要性 刀具管理是指对生产过程中使用的各种刀具进行计划、采购、存储、分配、使用、监控、维修和报废等全过程的管理。刀具作为制造过程中的直接工具&#xff0c;其性能、质量和使用效率直接影响产品的加工精度、表面质量和生产效率。因此&#xff0c;建…

算法学习(6)-最短路径

目录 Floyd-Warshall算法 Dijkstra算法 Bellman-Ford算法 Bellman-Ford的队列优化 最短路径算法对比分析 Floyd-Warshall算法 现在回到问题&#xff1a;如何求任意两点之间的最短路径呢&#xff1f; 通过之前的学习&#xff0c; 我们知道通过深度或广度优先搜索可以求出两…

【 npm详解:从入门到精通】

文章目录 npm详解&#xff1a;从入门到精通1. [npm](https://www.npmjs.com/)的安装2. npm的基础用法2.1 初始化项目2.2 安装依赖2.3 卸载依赖2.4 更新依赖 3. npm的高级用法3.1 运行脚本3.2 使用npm scope3.3 使用npm link 4. npm资源5. 使用npm进行依赖树分析和可视化6. npm进…

使用Nuxt.js实现服务端渲染(SSR)

Nuxt.js 是一个基于 Vue.js 的框架&#xff0c;它提供了服务器端渲染&#xff08;SSR&#xff09;和静态站点生成&#xff08;SSG&#xff09;的能力&#xff0c;使开发者能够轻松地构建高效、优雅的前端应用。Nuxt.js 集成了许多开箱即用的功能和工具&#xff0c;帮助开发者快…

天诚人脸物联网锁+网约房管理系统为智慧酒店、民宿管理赋能

随着互联网技术的发展&#xff0c;“网约房”逐渐步入受众视野&#xff0c;在改变旅客入住模式和生活方式的同时&#xff0c;为旅客旅游住宿创造了新的选择&#xff0c;也为拥有冗余房间资源的房东提供了新的营收路径。但是&#xff0c;网约房的管理问题频发&#xff0c;需要数…

springcloud alibaba微服务框架涉及的技术

一、微服务架构中核心模块及其使用技术总览 二、各模块详细说明 1、注册中心 该模块主要功能为 自动提供服务的注册与发现&#xff0c;集中式管理服务&#xff0c;让 服务调用端发现服务&#xff0c;让服务提供端注册服务&#xff0c;倘若没有注册中心&#xff0c;那客户端就…

Navicat导出表结构到Excel或Word

文章目录 sql语句复制到excel复制到Word sql语句 SELECTcols.COLUMN_NAME AS 字段,cols.COLUMN_TYPE AS 数据类型,IF(pks.CONSTRAINT_TYPE PRIMARY KEY, YES, NO) AS 是否为主键,IF(idxs.INDEX_NAME IS NOT NULL, YES, NO) AS 是否为索引,cols.IS_NULLABLE AS 是否为空,cols.…

小巧设备,大能量:探索口袋中的远程控制神器

在这个科技日新月异的时代&#xff0c;我们的生活被各种手机软件所包围。几乎每个人都有一个甚至多个手机&#xff0c;你是否也有遇到过需要远程操作自己某一台手机的场景呢&#xff1f;今天&#xff0c;我要向大家推荐一款神奇的手机远程操作神器&#xff0c;让你可以随时随地…

未授权访问:MongoDB未授权访问漏洞

目录 1、漏洞原理 2、环境搭建 3、未授权访问 防御手段 今天继续学习各种未授权访问的知识和相关的实操实验&#xff0c;一共有好多篇&#xff0c;内容主要是参考先知社区的一位大佬的关于未授权访问的好文章&#xff0c;还有其他大佬总结好的文章&#xff1a; 这里附上大佬…

【Chrome实用命令笔记】

文章目录 Chrome实用命令笔记1、chrome基本介绍2. 打开开发者工具&#xff08;DevTools&#xff09;方法一&#xff1a;快捷键方法二&#xff1a;右键菜单方法三&#xff1a;浏览器设置 2. 开发者工具面板Elements面板Console面板Sources面板Network面板Performance面板Memory面…

HTML Audio标签src使用base64字符

源码&#xff1a; <!DOCTYPE html> <html> <head> <meta charset"utf-8"> <title>Audio src base64</title> </head> <body><audio controls><source src"data:audio/mp3;base64,//OIxAAAAAAAAAA…

SpringBoot:SpringBoot:实战项目TILAS智能学习辅助系统1.3

登录认证 需求:输入登录请求服务器判断用户的用户名和密码 //控制层 PostMapping("/login")public Result login(RequestBody Emp emp);Overridepublic Result login(Emp emp) {Emp emp1 empService.selectLogin(emp);if(emp1 null){System.out.println("用…

虚拟化技术 使用Vsphere Client管理ESXi服务器系统

使用Vsphere Client管理ESXi服务器系统 一、实验目的与要求 1.掌握使用vSphere Client管理ESXi主机 2.掌握将CentOS的安装介质ISO上传到ESXi存储 3.掌握在VMware ESXi中创建虚拟机 4.掌握在所创建的虚拟机中安装CentOS6.5操作系统 5.掌握给CentOS6.5安装VMware Tools 6.掌…

uniapp0基础编写安卓原生插件之编写安卓页面在uniapp上显示(摄像头调用)

前言 如果你对安卓插件开发部分不熟悉你可以先看uniapp0基础编写安卓原生插件和调用第三方jar包和编写语音播报插件之零基础编写安卓插件 效果 开始 dcloud_uniplugins.json {"nativePlugins": [{"hooksClass": "","plugins": [{&…

【qt】核心机制信号槽(下)

这里写目录标题 自定义的信号自定义的槽自定义的信号和槽的结合使用信号和槽的断开总结&#xff1a; 自定义的信号 信号就是一个函数声明 前面咱们都用的qt组件自带的信号&#xff0c;接下来我们自己写一个信号。 信号只需要在前面加一个signals即可 这个函数不需要实现 参数传…

Grounded-Segment-Anything实现自动文本标注

项目地址&#xff1a;IDEA-Research/Grounded-Segment-Anything: Grounded-SAM: Marrying Grounding-DINO with Segment Anything & Stable Diffusion & Recognize Anything - Automatically Detect , Segment and Generate Anything (github.com) demo地址&#xff1a…

Blender材质,纹理,UV

1.材质Material&#xff0c;用于描述物体的表面性质&#xff0c;包含以下基本属性 -基础色 -金属/非金属 -粗糙度 -透光度 -凹凸细节 添加材质步骤&#xff1a; 1&#xff09;切换到材质预览模式 2&#xff09;打开材质面板 3&#xff09;添加一个材质&#xff0c;包括材…