【4.8】图搜索算法-BFS解单词接龙

一、题目

        给 定 两 个 单 词 ( beginWord endWord ) 和 一 个 字 典 , 找 到 从 beginWord
endWord 的最短转换序列的长度。转换需遵循如下规则:
1. 每次转换只能改变一个字母。
2. 转换过程中的中间单词必须是字典中的单词。
说明 :
1、如果不存在这样的转换序列,返回 0。
2、 所有单词具有相同的长度。
3、所有单词只由小写字母组成。
4、 字典中不存在重复的单词。
5、你可以假设 beginWord 和 endWord 是非空的,且二者不相同。

示例 1:

示例 2:

二、解题思路

解决方式一(一圈一圈往外扩散):

        以beginWord为起点,将其视为第一圈。接着,将字典中与beginWord仅有一个字符差异的单词归入第二圈。随后,将与第二圈单词仅有一个字符差异且在字典中存在的单词纳入第三圈……以此类推。在扩展过程中,需确保不重复纳入已出现的单词,并且在遇到endWord时立即返回。

这里以示例1为例画个图看看

解决方式二(从两边往中间开始计算):

        上述方法是从start开始向外扩散,但也可以采用双向扩散的策略:同时从start和end向中间推进。在每一步中,优先遍历元素较少的圈,这样可以减少循环的次数。如果在某个圈中相遇,则立即返回结果。

三、代码实现

方式一代码:

#include <iostream>
#include <vector>
#include <string>
#include <unordered_set>
#include <queue>using namespace std;int ladderLength(string beginWord, string endWord, vector<string>& wordList) {// 把字典中的单词放入到set中,主要是为了方便查询unordered_set<string> dictSet(wordList.begin(), wordList.end());// 创建一个新的单词,记录单词是否被访问过,如果没被访问过就加入进来unordered_set<string> visit;// BFS中常见的队列,我们可以把它想象成为一颗二叉树,记录每一层的节点。// 或者把它想象成为一个图,记录挨着的节点,也就是每一圈的节点。这里我们把它想象成为一个图queue<string> queue;queue.push(beginWord);// 这里的图是一圈一圈往外扩散的,这里的minlen可以看做扩散了多少圈,// 也就是最短的转换序列长度int minlen = 1;while (!queue.empty()) {// 这里找出每个节点周围的节点数量,然后都遍历他们int levelCount = queue.size();for (int i = 0; i < levelCount; i++) {// 出队string word = queue.front();queue.pop();// 这里遍历每一个节点的单词,然后修改其中一个字符,让他成为一个新的单词,// 并查看这个新的单词在字典中是否存在,如果存在并且没有被访问过,就加入到队列中for (int j = 0; j < word.length(); j++) {char ch[word.length()];strcpy(ch, word.c_str());for (char c = 'a'; c <= 'z'; c++) {if (c == word[j])continue;ch[j] = c;// 修改其中的一个字符,然后重新构建一个新的单词string newWord(ch);// 查看字典中有没有这个单词,如果有并且没有被访问过,就加入到队列中// (unordered_set的insert方法表示把单词加入到队列中,如果set中没有这个单词// 就会添加成功,返回true。如果有这个单词,就会添加失败,返回false)if (dictSet.find(newWord) != dictSet.end() && visit.insert(newWord).second) {// 如果新单词是endWord就返回,这里访问的是第minlen圈的节点,然后// 新建的节点就是第minlen+1层if (newWord == endWord)return minlen + 1;queue.push(newWord);}}}}// 每往外扩一圈,长度就加1minlen++;}return 0;
}int main() {string beginWord = "hit";string endWord = "cog";vector<string> wordList = {"hot", "dot", "dog", "lot", "log", "cog"};int result = ladderLength(beginWord, endWord, wordList);cout << "The shortest transformation sequence length is: " << result << endl;return 0;
}

方式二代码:

#include <iostream>
#include <vector>
#include <string>
#include <unordered_set>
#include <queue>using namespace std;int find(int minlen, queue<string>& startQueue, queue<string>& endQueue, unordered_set<string>& dictSet, unordered_set<string>& visit) {int startCount = startQueue.size();int endCount = endQueue.size();bool start = startCount <= endCount;int count = start ? startCount : endCount;// 哪个量少,遍历哪个for (int i = 0; i < count; i++) {// 出队string word;if (start)word = startQueue.front();elseword = endQueue.front();if (start)startQueue.pop();elseendQueue.pop();// 这里遍历每一个节点的单词,然后修改其中一个字符,让他成为一个新的单词,// 并查看这个新的单词在字典中是否存在,如果存在并且没有被访问过,就加入到队列中for (int j = 0; j < word.length(); j++) {char ch[word.length() + 1];strcpy(ch, word.c_str());for (char c = 'a'; c <= 'z'; c++) {if (c == word[j])continue;ch[j] = c;// 修改其中的一个字符,然后重新构建一个新的单词string newWord(ch);if (dictSet.find(newWord) != dictSet.end()) {if (start) { // 从前往后if (find(endQueue.begin(), endQueue.end(), newWord) != endQueue.end())return minlen + 1;if (visit.insert(newWord).second)startQueue.push(newWord);} else { // 从后往前if (find(startQueue.begin(), startQueue.end(), newWord) != startQueue.end())return minlen + 1;if (visit.insert(newWord).second)endQueue.push(newWord);}}}}}// 如果没有相遇就返回-1return -1;
}int main() {string beginWord = "hit";string endWord = "cog";vector<string> wordList = {"hot", "dot", "dog", "lot", "log", "cog"};unordered_set<string> dictSet(wordList.begin(), wordList.end());unordered_set<string> visit;queue<string> startQueue;queue<string> endQueue;startQueue.push(beginWord);endQueue.push(endWord);int minlen = 1;int result = find(minlen, startQueue, endQueue, dictSet, visit);cout << "The shortest transformation sequence length is: " << result << endl;return 0;
}
这道题上两种方式都能解决,第2种方式比第一种稍微要复杂一些,但运行效率要比第1种高。

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

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

相关文章

JavaScript 网页设计案例:使用 Canvas 实现趣味打气球小游戏

JavaScript 网页设计案例&#xff1a;使用 Canvas 实现趣味打气球小游戏 在网页设计中&#xff0c;交互性和趣味性是吸引用户的重要因素。借助 JavaScript 和 HTML5 的 canvas 元素&#xff0c;我们可以轻松实现各种动画效果&#xff0c;今天将带你打造一个有趣的 打气球小游戏…

【银行科技岗】相关考试知识点总结及部分考题

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 一、**网络与安全**二、**软件开发与设计**三、**数据库与数据管理**四、**编程与系统**五、**计算机硬件与性能**六、**大数据与人工智能**七、**系统与应用**相关…

dfs +剪枝sudoku———poj2676

目录 前言 lowbit函数 数独 suduku 问题描述 输入 输出 问题分析 子网格位置 优化搜索顺序剪枝1 优化搜索顺序剪枝2 可行性剪枝 代码 前言 lowbit函数 这是一个利用二进制位运算取出二进制数最后一位’1‘的函数 数独 数独大家肯定都玩过&#xff0c;…

<<迷雾>> 第11章 全自动加法计算机(7)--部分自动化加法 示例电路

部分实现了自动化的连续加法电路. info::操作说明 增加了译码器模块, 把从内存中取数的步骤和装载/相加的步骤综合起来, 总共五步骤 存储器中已经提前预存了 5 个数. 如果地址计数器 AC 还没有清零, 则需要先清零. 闭合 K装载 开关, 断开 K相加 开关 将开关 K 连续按 5 次, 第…

SpringMVC后台控制端校验-表单验证深度分析与实战优化

前言 在实战开发中&#xff0c;数据校验也是十分重要的环节之一&#xff0c;数据校验大体分为三部分&#xff1a; 前端校验后端校验数据库校验 本文讲解如何在后端控制端进行表单校验的工作 案例实现 在进行项目开发的时候,前端(jquery-validate),后端,数据库都要进行相关的数据…

Java多线程面试题

一.Java多线程基础 1.进程和线程的区别 程序是由指令和数据组成&#xff0c;但这些指令要运行&#xff0c;数据要读写&#xff0c;就必须将指令加载至 CPU中&#xff0c;数据加载至内存。在指令运行过程中还需要用到磁盘、网络等设备。进程就是用来加载指令、管理内存、管理 I…

【C语言】动态内存管理及相关笔试题

文章目录 一、为什么有动态内存分配二、malloc和free1.malloc函数的使用2.free函数的使用 三、calloc和realloc1.calloc函数的使用2.realloc函数的使用 四、常见动态内存分配的错误五、动态内存经典笔试题题1题2题3 六、总结C/C中程序内存区域划分 一、为什么有动态内存分配 我…

【C语言刷力扣】2206.将数组划分成相等数对

题目&#xff1a; 解题思路&#xff1a; 题目中要求元素成数对出现&#xff0c;即每个元素出现偶数次。用哈希表存放每个数出现的次数&#xff0c;再循环查看每个数的次数是否位偶数。 typedef struct {int key;int count;UT_hash_handle hh; } hashEntry;bool divideArray(int…

数据库实验3视图

10-1 创建视图计算学生课程平均分 现有一个学生数据库&#xff0c;内包含学生表&#xff08;Student&#xff09;、课程表&#xff08;Course&#xff09;和选修表&#xff08;SC&#xff09;。 在每一学年&#xff0c;学生处需要统计每位学生的学习情况&#xff0c;以便进行…

(34)FFT与信号频谱(双边谱)

文章目录 前言一、仿真代码二、仿真结果画图 前言 本文首先使用MATLAB生成一段余弦信号&#xff0c;然后对其进行FFT变换&#xff0c;给出了信号的双边幅度谱。 一、仿真代码 代码如下&#xff08;示例&#xff09;&#xff1a; %% 生成余弦波 % 指定信号的参数&#xff0c;…

layui table 自定义表头

自定义表头-查询 js/css静态文件引用 <!-- 引入 layui.css --> <link href"//unpkg.com/layui2.9.16/dist/css/layui.css" rel"stylesheet"> <!-- 引入 layui.js --> <script src"//unpkg.com/layui2.9.16/dist/layui.js"…

算法 动态规划

更多文章&#xff1a;https://www.pandaer.space 动态规划 算法很简单&#xff01;今天我们来聊聊动态规划&#xff0c;我们先从动态规划怎么来的讲起&#xff0c;然后聊聊动态规划应该如何学&#xff1f;最后正式开始动态规划的学习之旅。 动态规划怎么就出现了呢&#xff…

串扰的耦合长度与串扰的关系

一、 名词解释 串扰&#xff1a;简单理解为两条或者多条信号线产生的耦合现象 攻击传输线&#xff08;侵略线&#xff09;&#xff1a;对其他线产生影响的线 受害传输线&#xff1a;被影响的线 串扰产生的原因&#xff0c;简单来说就是当线与线之间平行布线时&#xff0c;两…

2d实时数字人聊天语音对话使用案例,对接大模型

参看: https://github.com/wan-h/awesome-digital-human-live2d 电脑环境: ubuntu 1060ti 下载: git clone https://github.com/wan-h/awesome-digital-human-live2d.gitdocker部署; cd awesome-digital-human-live2d docker-compose -f docker-compose-quickStart.ya…

基于springboot的网页时装购物系统(含源码)

随着科学技术的飞速发展&#xff0c;社会的方方面面、各行各业都在努力与现代的先进技术接轨&#xff0c;通过科技手段来提高自身的优势&#xff0c;时装购物系统当然也不能排除在外。时装购物系统是以实际运用为开发背景&#xff0c;运用软件工程原理和开发方法&#xff0c;采…

Excel:vba实现禁止新增工作表

实现效果&#xff1a;禁止新增工作表 步骤如下&#xff1a; 1.点击开发工具里面的Visual Basic 2.不要自己创建&#xff0c;点击ThisWorkbook&#xff0c;点击选择Workbook&#xff0c;点击选择NewSheet 这里的NewSheet就是工作簿事件 代码如下&#xff1a; 这是事件处理程序…

Shell脚本:分发文件到各个集群节点

找一个全局目录/root/bin 写脚本 touch xsync chmod 777 xsync #!/bin/bash#作者&#xff1a;ldj #时间&#xff1a;2024-10-15 #描述&#xff1a;拷贝文件#1. 判断参数个数 if [ $# -lt 1 ]thenecho "Error: Not Enough Argument!"exit fi#2.遍历集群所有机器 spac…

两种Allan方差计算方法一致

陀螺仪数据使用西工大严老师开源代码avar函数计算方差和matlab2022自带allanvar函数计算其allan&#xff0c;两者计算一致。 方法一 tau0 0.01; [adev, tau, Err] avar(dataOne, tau0, str1); avarfit(adev, tau); %严老师开源程序拟合函数 结果&#xff1a;Q0.223 ; N0.…

QT实现校园导航

导航是地图类项目实战中经常会遇到了。看上去貌似没头绪&#xff0c;其实是有模板遵循的。我们直接根据图看代码。 //MainWidget.h#ifndef MAINWINDOW_H #define MAINWINDOW_H#include <QMainWindow> #include "mapwidget.h" #include <QToolButton> #in…

C++在vscode中的code runner配置/环境配置

C在vscode中快捷运行&#xff08;code runner&#xff09; 一、配置tasks.json 在vscode中创建文件夹或打开文件夹&#xff0c;会发现文件夹下多了一个.vscode文件夹&#xff0c;在该文件夹下创建tasks.json文件&#xff0c;并添加一下内容 {"version": "2.0…