《剑指 Offer》专项突破版 - 面试题 108 : 单词演变(C++ 实现)

目录

前言

单向广度优先搜索

双向广度优先搜索


 


前言

题目链接:单词演变

题目

输入两个长度相同但内容不同的单词(beginWord 和 endWord)和一个单词列表(wordList),求从 beginWord 到 endWord 的演变序列的最短长度,要求每步只能改变单词中的一个字母,并且演变过程中每步得到的单词都必须在给定的单词列表中。如果不能从 beginWord 演变到 endWord,则返回 0。假设所有单词只包含英文小写字母。

例如,如果 beginWord 为 "hit",endWord 为 "cog",wordList 为 ["hot", "dot", "dog", "lot", "log", "cog"],则演变序列的最短长度为 5,一个可行的演变序列为 "hit"->"hot"->"dot"->"dog"->"cog"。

分析

应用图相关算法的前提是找出图中的节点和边。这个问题是关于单词的演变的,所以每个单词就是图中的一个节点。如果两个单词能够相互演变(改变一个单词的一个字母就能变成另一个单词),那么这两个单词之间有一条边相连。例如,可以用下图表示 "hit"、"hot"、"dot"、"dog"、"lot"、"log"、"cog" 的演变关系,可以看出,从 "hit" 演变成 "cog" 的最短序列的长度为 5,一个可行的最短序列经过的节点用阴影表示。


单向广度优先搜索

这个题目要求计算最短演变序列的长度,即求图中两个节点的最短距离。表示单词演变的图也是一个无权图,按照题目的要求,图中两个节点的距离是连通两个节点的路径经过的节点的数目。通常用广度优先搜索计算无权图中的最短路径,广度优先搜索通常需要用到队列。

为了求得两个节点之间的最短距离,常见的解法是用两个队列实现广度优先搜索算法。一个队列 q1 中存放离起始节点距离为 d 的节点,当从这个队列中取出节点并访问的时候,与队列 q1 中相邻的节点离起始节点的距离都是 d + 1,将这些相邻的节点存放到另一个队列 q2 中。当队列 q1 中的所有节点都访问完毕时,再访问队列 q2 中的节点,并将相邻的节点放入 q1 中。可以交替使用 q1 和 q2 这两个队列由近及远地从起始节点开始搜索所有节点

class Solution {
public:int ladderLength(string beginWord, string endWord, vector<string>& wordList) {unordered_set<string> notVisited(wordList.begin(), wordList.end());queue<string> q1, q2;q1.push(beginWord);int length = 1;while (!q1.empty()){string word = q1.front();q1.pop();if (word == endWord)return length;vector<string> neighbors = getNeighbors(word);for (string& neighbor : neighbors){if (notVisited.count(neighbor)){q2.push(neighbor);notVisited.erase(neighbor);}}
​if (q1.empty()){q1 = q2;q2 = queue<string>();++length;}}return 0;}
private:vector<string> getNeighbors(string& word) {vector<string> neighbors;for (int i = 0; i < word.size(); ++i){char old = word[i];for (char ch = 'a'; ch <= 'z'; ++ch){if (ch != old){word[i] = ch;neighbors.push_back(word);}}word[i] = old;}return neighbors;}
};

上述代码首先将起始节点 beginWord 添加到队列 q1 中。接下来每一步从队列 q1 中取出一个节点 word 访问。如果 word 就是目标节点,则搜索结束;否则找出所有与 word 相邻的节点并将相邻的节点放到队列 q2 中。当队列 q1 中的所有节点都访问完毕时交换队列 q1 和 q2,以便接下来访问原来存放在队列 q2 中的节点。每次交换队列 q1 和 q2 都意味着距离初始结点距离为 d 的节点都访问完毕,接下来将访问距离为 d + 1 的节点,因此距离值增加 1

上述代码将单词列表中还没有访问过的节点放入 notVisited 中,每当一个单词被访问过就从这个 unordered_set 中删除。如果一个节点不在 notVisited 中,要么它不在单词列表之中,要么之前已经访问过,不管是哪种情况这个节点都可以忽略


双向广度优先搜索

这个题目是关于单一起始节点、单一目标节点的最短距离问题。前面的解法是从起始节点出发不断朝着目标节点的方向搜索,直到到达目标节点。针对这类问题有一种常用的优化方法,即在从起始节点出发不断朝着目标节点的方向搜索的同时,也从目标节点出发不断朝着起始节点的方向搜索。这种双向搜索的方法能够缩小搜索空间,从而提高搜索效率

下图是双向广度优先搜索缩小搜索空间的示意图。假设目标是求出图中顶部的黑色节点到底部的黑色节点的最短距离。如果采用广度优先搜索,那么图中所有节点都可能会被搜索到,如下图 (a) 所示。如果采用双向广度优先搜索,则分别从起始节点和目标节点出发不断搜索,直到在中间某个位置相遇,那么图中只有部分节点被搜索到,如下图 (b) 所示。

class Solution {
public:int ladderLength(string beginWord, string endWord, vector<string>& wordList) {unordered_set<string> notVisited(wordList.begin(), wordList.end());if (notVisited.count(endWord) == 0)return 0;unordered_set<string> s1, s2;s1.insert(beginWord), s2.insert(endWord);int length = 2;while (!s1.empty() && !s2.empty()){if (s2.size() < s1.size())s1.swap(s2);unordered_set<string> s3;for (const string& word : s1){vector<string> neighbors = getNeighbors(word);for (string& neighbor : neighbors){if (s2.count(neighbor))return length;if (notVisited.count(neighbor)){s3.insert(neighbor);notVisited.erase(neighbor);}}}++length;s1 = s3;}return 0;}
private:vector<string> getNeighbors(const string& word) {string tmp = word;vector<string> neighbors;for (int i = 0; i < tmp.size(); ++i){char old = tmp[i];for (char ch = 'a'; ch <= 'z'; ++ch){if (ch != old){tmp[i] = ch;neighbors.push_back(tmp);}}tmp[i] = old;}return neighbors;}
};

在上述代码中,s1 和 s2 分别存放两个方向上当前需要访问的节点,s3 用来存放与当前访问的节点相邻的节点。之所以这里用的是 unordered_set 而不是 queue,是因为需要判断从一个方向搜索到的节点在另一个方向是否已经访问过。只需要 O(1) 的时间就能判断 unordered_set 中是否包含一个元素

先将起始节点 beginWord 添加到 s1 中,将目标节点 endWord 添加到 s2 中。接下来每次 while 循环都是从需要访问的节点数目少的方向搜索,这样做是为了缩小搜索的空间。先确保 s1 中需要访问的节点数更少,接下来访问 s1 中的每个节点 word。如果某个与节点 word 相邻的节点 neighbor 在 s2 中,则说明两个不同方向的搜索相遇,已经找到了一条起始节点和目标节点之间的最短路径,此时路径的长度就是它们之间的最短距离,否则将节点 neighbor 添加到 s3 中。当 s1 中所有的节点都访问完毕,接下来可能会访问 s1 的节点的相邻节点,即 s3 中的节点,因此将 s1 指向 s3。然后继续从 s1 和 s2 中选择一个节点数目少的方向进行新一轮的搜索。每轮搜索都意味着在起始节点和目标节点之间的最短路径上多前进了一步,因此变量 length 增加 1

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

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

相关文章

HTML5+CSS3小实例:荧光图标悬停效果

实例:荧光图标悬停效果 技术栈:HTML+CSS 字体图标库:font-awesome 效果: 源码: 【HTML】 <!DOCTYPE html> <html lang="zh-CN"><head><meta charset="UTF-8"><meta name="viewport" content="width=d…

VulNyx - Ready

目录 信息收集 arp nmap nikto Redis未授权访问漏洞 漏洞扫描 redis-cli 写入公钥 ssh连接 get root.txt 信息收集 arp ┌─[rootparrot]─[~/vulnyx] └──╼ #arp-scan -l Interface: enp0s3, type: EN10MB, MAC: 08:00:27:16:3d:f8, IPv4: 192.168.9.102 Starti…

ZFT9 7VE8033同期脉冲发送装置 JSOEF约瑟

系列型号 ZFT9(PIG) 7VE8033同期脉冲发送装置; ZFT9(PIG) 7VE8043同期脉冲发送装置; ZFT9 7VE8033同期脉冲发送装置; ZFT9 7VE8043同期脉冲发送装置; 用途&#xff1a; ZFT9(PIG)同期脉冲发送装置用于船舶的三相系统&#xff0c;根据发电机和电力系统之间电压差、相位差、频率…

SAP SD学习笔记05 - SD中的一括处理(集中处理),出荷和请求的冻结(替代实现承认功能)

上一章讲了SD的重要概念&#xff0c;比如出荷Plant&#xff08;交货工厂&#xff09;&#xff0c;出荷Point&#xff08;装运点&#xff09;&#xff0c;输送计划&#xff0c;品目的可用性检查&#xff0c;一括纳入/分割纳入&#xff0c;仓库管理等。 SAP SD学习笔记04 - 出荷…

凡泰极客亮相2024 亚马逊云科技出海全球化论坛,为企业数字化出海赋能

随着「不出海&#xff0c;即出局」登上热搜榜单&#xff0c;企业出海已成燎原之势&#xff0c;3月29日&#xff0c;2024 亚马逊云科技出海全球化论坛在深圳成功举办&#xff0c;凡泰极客创始人梁启鸿受邀出席&#xff0c;并以 「App 2.0&#xff1a;以SuperApp构建智能数字生态…

K8s下部署grafana

1. 系统要求 最小化的软硬件要求 最小化硬件要求 磁盘空间: 1 GB内存: 750 MiB (approx 750 MB)CPU: 250m (approx 2.5 cores) 2. k8s部署grafana步骤 1) 创建名字空间 kubectl create namespace my-grafana 2) 创建yaml vim grafana.yaml yaml包含如下三个资源对象 Ob…

【七 (4)FineBI FCP模拟试卷-电站数据分析】

目录 文章导航一、字段解释1、电站基础信息表2、电站事实表 二、需求三、操作步骤1、将新增一列日期12、以左关联的形式增加装机容量3、年度发电总量4、年度售电完成率4、发电量及发电效率5、年售电完成比、售电回款比、管理费用比、运维费用比5、总装机容量6、最近日期7、最近…

Java基础-知识点03(面试|学习)

Java基础-知识点03 String类String类的作用及特性String不可以改变的原因及好处String、StringBuilder、StringBuffer的区别String中的replace和replaceAll的区别字符串拼接使用还是使用StringbuilderString中的equal()与Object方法中equals()区别String a new String("a…

使用 Docker 部署 Open-Resume 在线简历平台

1&#xff09;Open-Resume 介绍 GitHub&#xff1a; https://github.com/xitanggg/open-resume Open-Resume 是一款功能强大的开源 简历生成器 和 简历解析器 。可以帮助我们快速的生成个人简历&#xff0c;并定制化不同的主题和布局风格。该项目的目标是为每个人提供免费的现…

java数据结构与算法刷题-----LeetCode1009. 十进制整数的反码

java数据结构与算法刷题目录&#xff08;剑指Offer、LeetCode、ACM&#xff09;-----主目录-----持续更新(进不去说明我没写完)&#xff1a;https://blog.csdn.net/grd_java/article/details/123063846 文章目录 476题相同解法 476题相同解法 解题思路&#xff1a; 因为此题和…

【I/O】基于事件驱动的 I/O 模型---Reactor

Reactor 模型 BIO 到 I/O 多路复用 为每个连接都创建一个线程 假设我们现在有一个服务器&#xff0c;想要对接多个客户端&#xff0c;那么最简单的方法就是服务端为每个连接都创建一个线程&#xff0c;处理完业务逻辑后&#xff0c;随着连接关闭线程也要销毁&#xff0c;但是…

每日一题---移除元素

文章目录 1.题目名称2.题目思路2.1.思路1:2.2.思路2&#xff1a; 3.参考代码 每日一题—移除元素 1.题目名称 2.题目思路 2.1.思路1: 创建一个新的数组&#xff0c;将值不为val的放到新的数组&#xff0c;然后在返回新的数组的大小&#xff0c;但是题目专门说啦&#xff0c;这…

Big Data and Cognitive Computing (IF=3.7) 期刊投稿

Special Issue: Artificial Cognitive Systems for Computer Vision 欢迎计算机视觉相关工作的投稿&#xff01; 影响因子3.7&#xff0c;截止时间2024年12月31日 投稿咨询&#xff1a;lqyan18fudan.edu.cn 投稿网址&#xff1a;https://www.mdpi.com/journal/BDCC/special_iss…

Nature Machine Intelligence 纽约大学团队提出基于深度学习和语音生成技术的脑电-语音解码

由于神经系统的缺陷导致的失语会导致严重的生活障碍&#xff0c;它可能会限制人们的职业和社交生活。近年来&#xff0c;深度学习和脑机接口&#xff08;BCI&#xff09;技术的飞速发展为开发能够帮助失语者沟通的神经语音假肢提供了可行性。开发神经-语音解码器的尝试大多数依…

CSS之固定定位、相对定位、绝对定位

一、相对定位 相对元素自身所在的原来的位置进行定位&#xff0c;可以设置 left&#xff0c;right&#xff0c;top&#xff0c;bottom四个属性。 效果&#xff1a;在进行相对定位以后&#xff0c;元素原来所在的位置被保留了&#xff0c;既保留占位&#xff0c;其他元素的位置…

CSS核心样式-02-盒模型属性及扩展应用

目录 三、盒模型属性 常见盒模型区域 盒模型图 盒模型五大属性 1. 宽度 width 2. 高度 height 3. 内边距 padding 四值法 三值法 二值法 单值法 案例 4. 边框 border 按照属性值的类型划分为三个单一属性 ①线宽 border-width ②线型 border-style ③边框颜色 bo…

Python数据分析案例40——电商直播间成交金额预测

承接上一篇案例电商直播间提取的特征&#xff0c;进而做一篇机器学习的案例&#xff0c;来预测直播间的成交金额。 Python数据分析案例39——电商直播间评论可视化分析&#xff08;LDA&#xff09; 1. 引言 1.1 直播电商与传统电商的比较 直播电商作为一种新兴的电子商务模式…

超详细的YOLOv8项目组成解析:一站式指南了解其架构与组件

目录 yolov8导航 YOLOv8&#xff08;附带各种任务详细说明链接&#xff09; 项目结构 1. .github 2. docker 2.1 docker/Dockerfile 2.2 docker/Dockerfile-arm64 2.3 docker/Dockerfile-conda 2.4 docker/Dockerfile-cpu 2.5 docker/Dockerfile-jetson 2.6 docker/D…

Java | Leetcode Java题解之第27题移除元素

题目&#xff1a; 题解&#xff1a; class Solution {public int removeElement(int[] nums, int val) {int left 0;int right nums.length;while (left < right) {if (nums[left] val) {nums[left] nums[right - 1];right--;} else {left;}}return left;} }

MySQL之索引失效、覆盖、前缀索引及单列、联合索引详细总结

索引失效 最左前缀法则 如果索引了多列(联合索引)&#xff0c;要遵守最左前缀法则&#xff0c;最左前缀法则指的是查询从索引的最左列开始&#xff0c;并且不跳过索引中的列。如果跳跃某一列&#xff0c;索引将部分失效&#xff08;后面的字段索引失效&#xff09;。 联合索…