当前位置: 首页 > news >正文

算法训练之BFS解决最短路径问题


♥♥♥~~~~~~欢迎光临知星小度博客空间~~~~~~♥♥♥

♥♥♥零星地变得优秀~也能拼凑出星河~♥♥♥

♥♥♥我们一起努力成为更好的自己~♥♥♥

♥♥♥如果这一篇博客对你有帮助~别忘了点赞分享哦~♥♥♥

♥♥♥如果有什么问题可以评论区留言或者私信我哦~♥♥♥

✨✨✨✨✨✨ 个人主页✨✨✨✨✨✨

        这一篇博客我们继续来应用BFS算法解决一些具体问题,准备好了吗~我们发车去探索BFS的奥秘啦~🚗🚗🚗🚗🚗🚗

目录

迷宫中离入口最近的出口😁

最小基因变化😊

单词接龙😝

为高尔夫比赛砍树🙃

迷宫中离入口最近的出口😁

迷宫中离入口最近的出口

🧠 算法思路

BFS 初始化:从入口开始,步数初始为 0

逐层扩展:每次处理一层的所有节点,步数 +1

判断出口

        出口是边界上的空格子(maze[cx][cy] == '.')

        出口不能是入口

剪枝

        遇到墙('+')跳过,已访问的格子不再处理~

结果

        找到出口 → 返回当前步数

        队列为空仍未找到 → 返回 -1

代码实现

//迷宫中离入口最近的出口
class Solution
{typedef pair<int, int> PII;//方便写类型//方便遍历某一个位置上下左右四个方向int dx[4] = { 0,0,-1,1 };int dy[4] = { -1,1,0,0 };bool vis[101][101];//记录是否被访问int m = 0, n = 0;//记录行列
public:int nearestExit(vector<vector<char>>& maze, vector<int>& entrance){//获取行列m = maze.size();n = maze[0].size();queue<PII> q;//队列保存位置q.push({ entrance[0],entrance[1] });//入口入队列标记为被访问,不会成为出口vis[entrance[0]][entrance[1]] = true;int step = 0;//记录步数while (q.size()){step++;int sz = q.size();//处理当前层for (int i = 0; i < sz; i++){auto [qx, qy] = q.front();q.pop();for (int k = 0; k < 4; k++){int cx = qx + dx[k], cy = qy + dy[k];if (cx >= 0 && cx < m && cy >= 0 && cy < n && maze[cx][cy] == '.' && !vis[cx][cy]){//到达边界,返回步数if (cx == 0 || cx == m - 1 || cy == 0 || cy == n - 1){return step;}q.push({ cx,cy });vis[cx][cy] = true;}}}}//不存在路径,返回-1return -1;}
};

顺利通过~

最小基因变化😊

最小基因变化

🧠算法思路

1. 预处理与边界检查

    检查起始基因是否等于目标基因(直接返回0)

    验证目标基因是否存在于基因库中(不存在则返回-1)

    将基因库转换为哈希集合以提高查找效率

2. BFS初始化

    创建队列并将起始基因加入队列

    建立已访问集合,记录已处理过的基因序列

    初始化步数计数器为0

3. 层序遍历策略

    按层处理队列中的基因序列

    每处理完一层,步数增加1

    确保找到的路径是最短路径

4. 基因变化生成

    对当前基因序列的每个位置(共8个)

    尝试替换为其他三种可能的碱基(A/C/G/T)

    生成所有可能的单次突变结果

5. 有效性验证

    检查新生成的基因是否在基因库中

    验证该基因是否已被访问过

    避免重复处理相同状态

6. 目标检测

    比较新生成的基因与目标基因

    若匹配则立即返回当前步数

    否则加入队列继续搜索

7. 终止条件

    成功找到目标基因 → 返回变化次数

    队列耗尽仍未找到 → 返回-1(无解)

代码实现

//最小基因变化
class Solution
{
public:int minMutation(string startGene, string endGene, vector<string>& bank){//记录已经生成的字符串unordered_set<string> vis;//使用unordered_set保存基因库,方便查找unordered_set<string> ban(bank.begin(), bank.end());//处理边界特殊情况if (startGene == endGene)return 0;if (!ban.count(endGene))return -1;//变化字符string change = "AGCT";//记录变化次数int step = 0;queue<string> q;q.push(startGene);vis.insert(startGene);while (q.size()){int sz = q.size();step++;while (sz--){string qs = q.front();q.pop();//逐个修改当前字符串每一个字符for (int i = 0; i < 8; i++){string tmp = qs;for (int k = 0; k < 4; k++){tmp[i] = change[k];//没有被访问并且在基因库中if (!vis.count(tmp) && ban.count(tmp)){if (tmp == endGene)return step;q.push(tmp);vis.insert(tmp);}}}}}//没有结果,返回-1return -1;}
};

顺利通过~

单词接龙😝

单词接龙

        这一个题目与前面一个题目是类似的,我们一样首先来看看算法思路~

🧠算法思路

1. 数据预处理

    将 wordList 转换为哈希集合,实现O(1)时间复杂度的查找

    创建已访问集合,避免重复处理相同单词

2. 边界条件检查

    检查 endWord 是否在单词列表中(不在则直接返回0)

    题目提示 beginWord ≠ endWord,可选择性处理相等情况

3. BFS初始化

    初始化步数计数器为1(包含起始单词)

    将 beginWord 加入队列和已访问集合

4. 分层遍历策略

    按层处理队列中的单词

    每处理完一层,步数增加1

    确保找到的路径是最短的

5. 单词变换生成

    对当前单词的每个位置

    尝试替换为26个小写字母中的每一个

    生成所有可能的单字母差异单词

6. 有效性验证

    检查新单词是否在单词列表中

    验证该单词是否已被访问过

7. 目标检测与终止

    如果新单词等于 endWord,立即返回当前步数

    否则将有效新单词加入队列继续搜索

代码实现

//单词接龙
class Solution
{
public:int ladderLength(string beginWord, string endWord, vector<string>& wordList){//记录是否被访问unordered_set<string> vis;//记录字典中的单词unordered_set<string> words(wordList.begin(), wordList.end());//处理边界特殊情况if (beginWord == endWord)return 0;//这种特殊情况可以不处理,题目提示beginWord!=endWordif (!words.count(endWord))return 0;//记录变化字符串个数int step = 0;//获取字符串长度int sn = beginWord.size();//队列进行BFS遍历保存queue<string> q;q.push(beginWord);vis.insert(beginWord);step++;//第一个字符串也进行计数while (q.size()){step++;//字符串个数++int sz = q.size();while (sz--){string  qs = q.front();q.pop();//依次修改当前字符串的每一个字符for (int i = 0; i < sn; i++){string tmp = qs;for (char c = 'a'; c <= 'z'; c++){tmp[i] = c;if (!vis.count(tmp) && words.count(tmp)){if (tmp == endWord)return step;q.push(tmp);vis.insert(tmp);}}}}}//没有结果,返回0return 0;}
};

顺利通过~

为高尔夫比赛砍树🙃

为高尔夫比赛砍树

🧠算法思路

1. 数据预处理

    收集所有树的位置:遍历整个网格,记录所有高度大于1的树的位置

    按高度排序:根据树的高度值对位置进行升序排序,确定砍树顺序

2. 路径计算

    起点初始化:从(0,0)位置开始

    顺序访问树木:按照排序后的顺序依次访问每棵树

    累计步数:计算从当前位置到下一棵树的最短路径,并累加步数

BFS执行步骤

    初始化

        重置访问标记数组

        起点入队并标记为已访问

        步数计数器初始化为0

    分层遍历

        每次处理一层的所有节点

        每进入新的一层,步数增加1

        使用sz变量控制当前层节点数量

    邻居扩展

        对每个节点的四个方向进行探索

        检查边界条件、障碍物和访问状态

        发现目标立即返回当前步数

    终止条件

        找到目标位置 → 返回步数

        队列为空未找到 → 返回-1

3. 异常处理

    可达性检查:如果任何一棵树无法到达,立即返回-1

    起点终点相同:特殊处理,步数为0

代码实现


//为高尔夫比赛砍树
class Solution
{//方便写类型typedef pair<int, int> PII;//方便访问某一个位置上下左右四个方向int dx[4] = { 0,0,1,-1 };int dy[4] = { -1,1,0,0 };//记录行列int m = 0, n = 0;
public:int cutOffTree(vector<vector<int>>& forest){//获取行列m = forest.size();n = forest[0].size();//1、按照树的高度进行排序vector<PII> trees;for (int i = 0; i < m; i++){for (int j = 0; j < n; j++){if (forest[i][j] > 1){trees.push_back({ i,j });}}}//根据高度对位置进行排序sort(trees.begin(), trees.end(), [&](const PII& p1, const PII& p2) {return forest[p1.first][p1.second] < forest[p2.first][p2.second];});//2、根据排序顺序依次找到最短路径int step = 0;//记录步数int bx = 0, by = 0;//起点【0,0】for (auto& [ex, ey] : trees){int ret = bfs(forest, bx, by, ex, ey);//无法到达,不存在路径if (ret == -1)return -1;//可以到达累积步数step += ret;//更新起点bx = ex, by = ey;}//3、返回结果return step;}//记录是否被访问bool vis[51][51] = { false };//BFS计算两个位置最短路径int bfs(vector<vector<int>>& forest, int bx, int by, int ex, int ey){//处理边界特殊情况——起点就是指定位置if (bx == ex && by == ey)return 0;memset(vis, 0, sizeof vis);//清除之前的记录queue<PII> q;q.push({ bx,by });vis[bx][by] = true;int ret = 0;//记录最小步数while (q.size()){ret++;int sz = q.size();while (sz--){auto [qx, qy] = q.front();q.pop();for (int i = 0; i < 4; i++){int cx = qx + dx[i], cy = qy + dy[i];if (cx >= 0 && cx < m && cy >= 0 && cy < n && !vis[cx][cy] && forest[cx][cy])//不越界,不是墙,未被访问——三者同时满足{//到达指定位置(下一个位置)返回步数if (cx == ex && cy == ey)return ret;//否则入队列,标记被访问,继续后续操作q.push({ cx,cy });vis[cx][cy] = true;}}}}//不能到达指定位置,返回-1return -1;}
};

顺利通过~


♥♥♥本篇博客内容结束,期待与各位优秀程序员交流,有什么问题请私信♥♥♥

♥♥♥如果这一篇博客对你有帮助~别忘了点赞分享哦~♥♥♥

✨✨✨✨✨✨个人主页✨✨✨✨✨✨


http://www.dtcms.com/a/491618.html

相关文章:

  • h5手机端网站开发西安软件开发公司
  • DataFrame对象的iterrows()方法
  • 【Java零基础·第8章】面向对象(四):继承、接口与多态深度解析
  • 网站规划建设与管理维护大作业中国传统文化网页设计
  • 空气能空调如何做网站做酒店网站多少钱
  • 小道消息:某国产数据库迁移中途失败
  • AI+量化 的数据类型有哪些
  • 外贸网站如何seo推广常用网站如何在桌面做快捷方式
  • 遇到的问题:缺少ClickTo Run Service
  • [创业之路-699]:企业与高校:模式错配的警示与适配路径的探索
  • 电脑做系统都是英文选哪个网站怎么做局域网网站
  • 源丰建设有限公司网站如何做推广最有效果
  • 合规守护经营,道本科技智慧合同管理系统助力小微企业迈入发展快车道[赞啊][赞啊][赞啊]
  • 站点推广是什么意思wordpress双语插件
  • LLMs-from-scratch :embeddings 与 linear-layers 的对比
  • 量化交易的思维导图
  • 商城网站建设框架网站有哪些
  • 漏洞扫描POC和web漏洞扫描工具
  • go资深之路笔记(八) 基准测试
  • 第1讲:Go调度器GMP模型深度解析
  • C++ 关键字 static 面试高频问题汇总
  • 网站建设jnlongji百度技术培训中心
  • m版网站开发怎样创建网页
  • 基于自适应差分进化算法的MATLAB实现
  • 男人女人做那事网站如何创建一个互联网平台
  • RocketMQ 与 Kafka 架构与实现详解对比
  • 设计模式篇之 观察者模式 Observer
  • Tripo 3D AI 功能与技术解析
  • 千库网素材搜索引擎优化培训班
  • 能打开各种网站的浏览器appwordpress文章表情