单词接龙[中等]
一、题目
字典wordList
中从单词beginWord
和endWord
的 转换序列 是一个按下述规格形成的序列beginWord -> s1 -> s2 -> ... -> sk
:
1、每一对相邻的单词只差一个字母。
2、对于1 <= i <= k
时,每个si
都在wordList
中。注意,beginWord
不需要在wordList
中。
3、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
中的所有字符串 互不相同
二、代码
【1】广度优先搜索 + 优化建图: 本题要求的是最短转换序列的长度,看到最短首先想到的就是广度优先搜索。想到广度优先搜索自然而然的就能想到图,但是本题并没有直截了当的给出图的模型,因此我们需要把它抽象成图的模型。我们可以把每个单词都抽象为一个点,如果两个单词可以只改变一个字母进行转换,那么说明他们之间有一条双向边。因此我们只需要把满足转换条件的点相连,就形成了一张图。
基于该图,我们以beginWord
为图的起点,以endWord
为终点进行广度优先搜索,寻找beginWord
到endWord
的最短路径。
基于上面的思路我们考虑如何编程实现。首先为了方便表示,我们先给每一个单词标号,即给每个单词分配一个id
。创建一个由单词word
到id
对应的映射wordId
,并将beginWord
与wordList
中所有的单词都加入这个映射中。之后我们检查endWord
是否在该映射内,若不存在,则输入无解。我们可以使用哈希表实现上面的映射关系。
然后我们需要建图,依据朴素的思路,我们可以枚举每一对单词的组合,判断它们是否恰好相差一个字符,以判断这两个单词对应的节点是否能够相连。但是这样效率太低,我们可以优化建图。具体地,我们可以创建虚拟节点。对于单词hit
,我们创建三个虚拟节点*it
、h*t
、hi*
,并让hit
向这三个虚拟节点分别连一条边即可。如果一个单词能够转化为hit
,那么该单词必然会连接到这三个虚拟节点之一。对于每一个单词,我们枚举它连接到的虚拟节点,把该单词对应的id
与这些虚拟节点对应的id
相连即可。
最后我们将起点加入队列开始广度优先搜索,当搜索到终点时,我们就找到了最短路径的长度。注意因为添加了虚拟节点,所以我们得到的距离为实际最短路径长度的两倍。同时我们并未计算起点对答案的贡献,所以我们应当返回距离的一半再加一的结果。
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), endId = wordId.get(endWord);dis[beginId] = 0;Queue<Integer> que = new LinkedList<Integer>();que.offer(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.offer(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>());}}
}
时间复杂度: O(N×C^2)
。其中N
为wordList
的长度,C
为列表中单词的长度。
1、建图过程中,对于每一个单词,我们需要枚举它连接到的所有虚拟节点,时间复杂度为O(C)
,将这些单词加入到哈希表中,时间复杂度为O(N×C)
,因此总时间复杂度为O(N×C)
。
2、广度优先搜索的时间复杂度最坏情况下是O(N×C)
。每一个单词需要拓展出O(C)
个虚拟节点,因此节点数O(N×C)
。
空间复杂度: O(N×C^2)
。其中N
为wordList
的长度,C
为列表中单词的长度。哈希表中包含O(N×C)
个节点,每个节点占用空间O(C)
,因此总的空间复杂度为O(N×C^2)
。
双向广度优先搜索: 根据给定字典构造的图可能会很大,而广度优先搜索的搜索空间大小依赖于每层节点的分支数量。假如每个节点的分支数量相同,搜索空间会随着层数的增长指数级的增加。考虑一个简单的二叉树,每一层都是满二叉树的扩展,节点的数量会以2
为底数呈指数增长。如果使用两个同时进行的广搜可以有效地减少搜索空间。一边从beginWord
开始,另一边从endWord
开始。我们每次从两边各扩展一层节点,当发现某一时刻两边都访问过同一顶点时就停止搜索。这就是双向广度优先搜索,它可以可观地减少搜索空间大小,从而提高代码运行效率。
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[] disBegin = new int[nodeNum];Arrays.fill(disBegin, Integer.MAX_VALUE);int beginId = wordId.get(beginWord);disBegin[beginId] = 0;Queue<Integer> queBegin = new LinkedList<Integer>();queBegin.offer(beginId);int[] disEnd = new int[nodeNum];Arrays.fill(disEnd, Integer.MAX_VALUE);int endId = wordId.get(endWord);disEnd[endId] = 0;Queue<Integer> queEnd = new LinkedList<Integer>();queEnd.offer(endId);while (!queBegin.isEmpty() && !queEnd.isEmpty()) {int queBeginSize = queBegin.size();for (int i = 0; i < queBeginSize; ++i) {int nodeBegin = queBegin.poll();if (disEnd[nodeBegin] != Integer.MAX_VALUE) {return (disBegin[nodeBegin] + disEnd[nodeBegin]) / 2 + 1;}for (int it : edge.get(nodeBegin)) {if (disBegin[it] == Integer.MAX_VALUE) {disBegin[it] = disBegin[nodeBegin] + 1;queBegin.offer(it);}}}int queEndSize = queEnd.size();for (int i = 0; i < queEndSize; ++i) {int nodeEnd = queEnd.poll();if (disBegin[nodeEnd] != Integer.MAX_VALUE) {return (disBegin[nodeEnd] + disEnd[nodeEnd]) / 2 + 1;}for (int it : edge.get(nodeEnd)) {if (disEnd[it] == Integer.MAX_VALUE) {disEnd[it] = disEnd[nodeEnd] + 1;queEnd.offer(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>());}}
}
时间复杂度: O(N×C^2)
。其中N
为wordList
的长度,C
为列表中单词的长度。
1、建图过程中,对于每一个单词,我们需要枚举它连接到的所有虚拟节点,时间复杂度为O(C)
,将这些单词加入到哈希表中,时间复杂度为O(N×C)
,因此总时间复杂度为O(N×C)
。
2、双向广度优先搜索的时间复杂度最坏情况下是O(N×C)
。每一个单词需要拓展出O(C)
个虚拟节点,因此节点数O(N×C)
。
空间复杂度: O(N×C^2)
。其中N
为wordList
的长度,C
为列表中单词的长度。哈希表中包含O(N×C)
个节点,每个节点占用空间O(C)
,因此总的空间复杂度为O(N×C^2)
。
相关文章:

单词接龙[中等]
一、题目 字典wordList中从单词beginWord和endWord的 转换序列 是一个按下述规格形成的序列beginWord -> s1 -> s2 -> ... -> sk: 1、每一对相邻的单词只差一个字母。 2、对于1 < i < k时,每个si都在wordList中。注意,beg…...

机器人制作开源方案 | 森林管理员
作者:李佳骏、常睿康、张智斌、李世斌、高华耸 单位:山西能源学院 指导老师:赵浩成、郜敏 1. 研究背景 森林作为地球上可再生自然资源及陆地生态的主体,在人类生存和发展的历史中起着不可代替的作用,它不仅能提供…...

Laravel框架使用phpstudy本地安装的composer用Laravel 安装器进行安装搭建
一、首先需要安装Laravel 安装器 composer global require laravel/installer 二、安装器安装好后,可以使用如下命令创建项目 laravel new sys 三、本地运行 php artisan serve 四、 使用Composer快速安装Laravel5.8框架 安装指定版本的最新版本(推荐&a…...

炫酷登录注册界面【超级简单 jQuery+JS+HTML+CSS实现】
一:源码获取 这两天根据需求写了一个比较好看的有动态效果的登录注册切换页面,这里我将源码资源分享给大家,大家可以直接免费下载使用哦,没有 vip 的小伙伴找我私聊发送"登录注册"即可我给你发文件,此登录注…...

2023年国赛高教杯数学建模E题黄河水沙监测数据分析解题全过程文档及程序
2023年国赛高教杯数学建模 E题 黄河水沙监测数据分析 原题再现 黄河是中华民族的母亲河。研究黄河水沙通量的变化规律对沿黄流域的环境治理、气候变化和人民生活的影响,以及对优化黄河流域水资源分配、协调人地关系、调水调沙、防洪减灾等方面都具有重要的理论指导…...

跨国企业传输大文件注意事项和解决方案
随着全球化的推进,越来越多的企业需要在跨国业务合作、项目交付、数据分析等方面展开合作,这就带来了大量大文件的传输需求。大文件传输是指文件大小超过1GB的传输,通常涉及视频、音频、图片、文档、压缩包等多种格式。跨国传输大文件不仅需要…...
【Redis】Redis 的数据类型
有五种常用数据类型:String、Hash、Set、List、SortedSet。以及三种特殊的数据类型:Bitmap、HyperLogLog、Geospatial ,其中HyperLogLog、Bitmap的底层都是 String 数据类型,Geospatial 的底层是 Sorted Set 数据类型。 五种常用…...

QT小技巧 - 使用QMovie进行gif切帧
简介 使用QMovie 将 gif 进行切帧, magick 进行合并代码 QString gifPath "E:\\workspace\\qt\\gif2imgs\\203526qre64haq3ccoobqi.gif"; // 你的图片QMovie movie(gifPath); movie.setCacheMode(QMovie::CacheNone);qDebug() << movie.frameCou…...

ES-搜索
聚合分析 聚合分析,英文为Aggregation,是es 除搜索功能外提供的针对es 数据做统计分析的功能 - 功能丰富,提供Bucket、Metric、Pipeline等多种分析方式,可以满足大部分的分析需求 实时性高,所有的计算结果都是即时返回…...
微信小程序面试题
微信小程序面试题 请解释微信小程序的生命周期及其对应的钩子函数。 微信小程序的生命周期包括 onLaunch、onShow、onHide、onError、onPageNotFound 等阶段。对应的钩子函数分别是: onLaunch:小程序初始化时触发。onShow:小程序启动或从后台…...

OpenCV之图像匹配与定位
利用图像特征的keypoints和descriptor来实现图像的匹配与定位。图像匹配算法主要有暴力匹配和FLANN匹配,而图像定位是通过图像匹配结果来反向查询它们在目标图片中的具体坐标位置。 以QQ登录界面为例,将整个QQ登录界面保存为QQ.png文件,QQ登…...

掌握JWT:解密身份验证和授权的关键技术
JSON Web Token 1、什么是JWT2、JWT解决了什么问题3、早期的SSO认证4、JWT认证5、JWT优势6、JWT结构Header 标头Payload 负载 Signature 签名 7、代码实现添加依赖生成Token认证token 8、工具类9、JWT整合Web10、拦截器校验11、网关路由校验12、解决多用户登录的问题13、客户端…...

git命令和docker命令
1、git git是分布式的版本控制工具 git可以通过本地仓库管理文件的历史版本记录 # 本地仓库操作的命令 # 初始化本地库 git init # 添加文件到暂存区 git add . git checkout 暂存区要撤销的文件名称 # 提交暂存区文件 git commit -m 注释# 版本穿梭 # 查看提交记录 git log…...

【K8S in Action】服务:让客户端发现pod 并与之通信(2)
一 通过Ingress暴露服务 Ingress (名词) 一一进入或进入的行为;进入的权利;进入的手段或地点;入口。一个重要的原因是每个 LoadBalancer 服务都需要自己的负载均衡器, 以及 独有的公有 IP 地址, 而 Ingres…...
Spring Boot 中实现跨域的几种方式
前言 在现代Web应用中,由于安全性和隐私的考虑,浏览器限制了从一个域向另一个域发起的跨域HTTP请求。解决这个问题的一种常见方式是实现跨域资源共享(CORS)。Spring Boot提供了多种方式来处理跨域请求,本文将介绍其中的…...

WT2605C音频蓝牙语音芯片:单芯片实现蓝牙+MP3+BLE+电话本多功能应用
在当今的电子产品领域,多功能、高集成度成为了一种趋势。各种产品都需要具备多种功能,以满足用户多样化的需求。针对这一市场趋势,唯创知音推出了一款集成了蓝牙、MP3播放、BLE和电话本功能的音频蓝牙语音芯片——WT2605C,实现了单…...

计算机毕业设计 基于SpringBoot的高校宣讲会管理系统的设计与实现 Java实战项目 附源码+文档+视频讲解
博主介绍:✌从事软件开发10年之余,专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ 🍅文末获取源码联系🍅 👇🏻 精…...
Android 使用Serialiable接口和Parcelable接口进行数据传送
一、前言 这篇文章主要针对Serialiable和Parcelable接口来传递对象。呈现的功能是跳转到另一个界面,然后通过toast展现我收到的数据。 二、使用Serialiable接口传递数据 1.创建需要传递的对象 //必须实现Serializable接口,此对象才有传递的资格 publ…...

【数据结构入门精讲 | 第十七篇】一文讲清图及各类图算法
在上一篇中我们进行了的并查集相关练习,在这一篇中我们将学习图的知识点。 目录 概念深度优先DFS伪代码 广度优先BFS伪代码 最短路径算法(Dijkstra)伪代码 Floyd算法拓扑排序逆拓扑排序 概念 下面介绍几种在对图操作时常用的算法。 深度优先D…...

Python 直方图的绘制-`hist()`方法(Matplotlib篇-第7讲)
Python 直方图的绘制-hist()方法(Matplotlib篇-第7讲) 🍹博主 侯小啾 感谢您的支持与信赖。☀️ 🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹…...

(十)学生端搭建
本次旨在将之前的已完成的部分功能进行拼装到学生端,同时完善学生端的构建。本次工作主要包括: 1.学生端整体界面布局 2.模拟考场与部分个人画像流程的串联 3.整体学生端逻辑 一、学生端 在主界面可以选择自己的用户角色 选择学生则进入学生登录界面…...
逻辑回归:给不确定性划界的分类大师
想象你是一名医生。面对患者的检查报告(肿瘤大小、血液指标),你需要做出一个**决定性判断**:恶性还是良性?这种“非黑即白”的抉择,正是**逻辑回归(Logistic Regression)** 的战场&a…...

练习(含atoi的模拟实现,自定义类型等练习)
一、结构体大小的计算及位段 (结构体大小计算及位段 详解请看:自定义类型:结构体进阶-CSDN博客) 1.在32位系统环境,编译选项为4字节对齐,那么sizeof(A)和sizeof(B)是多少? #pragma pack(4)st…...
ssc377d修改flash分区大小
1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...

关键领域软件测试的突围之路:如何破解安全与效率的平衡难题
在数字化浪潮席卷全球的今天,软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件,这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下,实现高效测试与快速迭代?这一命题正考验着…...

以光量子为例,详解量子获取方式
光量子技术获取量子比特可在室温下进行。该方式有望通过与名为硅光子学(silicon photonics)的光波导(optical waveguide)芯片制造技术和光纤等光通信技术相结合来实现量子计算机。量子力学中,光既是波又是粒子。光子本…...

无人机侦测与反制技术的进展与应用
国家电网无人机侦测与反制技术的进展与应用 引言 随着无人机(无人驾驶飞行器,UAV)技术的快速发展,其在商业、娱乐和军事领域的广泛应用带来了新的安全挑战。特别是对于关键基础设施如电力系统,无人机的“黑飞”&…...

Linux 中如何提取压缩文件 ?
Linux 是一种流行的开源操作系统,它提供了许多工具来管理、压缩和解压缩文件。压缩文件有助于节省存储空间,使数据传输更快。本指南将向您展示如何在 Linux 中提取不同类型的压缩文件。 1. Unpacking ZIP Files ZIP 文件是非常常见的,要在 …...

免费数学几何作图web平台
光锐软件免费数学工具,maths,数学制图,数学作图,几何作图,几何,AR开发,AR教育,增强现实,软件公司,XR,MR,VR,虚拟仿真,虚拟现实,混合现实,教育科技产品,职业模拟培训,高保真VR场景,结构互动课件,元宇宙http://xaglare.c…...
Web中间件--tomcat学习
Web中间件–tomcat Java虚拟机详解 什么是JAVA虚拟机 Java虚拟机是一个抽象的计算机,它可以执行Java字节码。Java虚拟机是Java平台的一部分,Java平台由Java语言、Java API和Java虚拟机组成。Java虚拟机的主要作用是将Java字节码转换为机器代码&#x…...