bfs:打开转盘锁的最少次数(752)

2023-12-05 21:40
文章标签 最少 次数 bfs 打开 转盘 752

本文主要是介绍bfs:打开转盘锁的最少次数(752),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在这里插入图片描述

思路:
  这道题目挺有意思的,需要脑经稍微转下,感觉笔试出这种题目的话也是无可厚非。。搜索问题一开始想到dfs,dfs需要构建搜索树啊,怎么构建呢?可以看到一共是4个键,每次可以选择其中一个键上调或者下调,特殊情况是0和9的情况0下调是9,9上调是0.这样每次操作就8个,时间复杂度就是8的n次方,那什么时候结束呢,题目设置了不能走禁区组合,走到就锁住了,如果只是不能触碰禁区没有其他条件如果走不到目标组合就一直走了,==所以我们每次走过的路都存入哈希表。==如果走过,下次就不走了,因为再走就是走老路,这步数肯定不比上次少。直到无路可走,因为都走过了。那就结束
  但是用深度优先搜索的话这个判断机制还是比较难写。因为我们只要走到就行,这种题目适合bfs广度优先。每个节点扩张节点,走过就不扩张,直到走完!
注意到子函数必须写在主函数外面,leetcode官方题目把子函数写在里面了,所以用了不同的方式,我们还是走常规路线把。
但是还是来学习下,这个定义都是auto开头,get是函数名,然后= ,方括号如果虚拟变量要索引就把索引加到方括号,小括号是虚拟变量->给输出的变量类型,这样就定义好了.

 auto get = [&](string& status) -> vector<string

注意到当输出是空的时候是这个形式,前面是function和void

function<void(int, int)> dfs = [&](int index, int steps)

下面附上bfs的代码:

class Solution {
public:char num_prev(char x){return (x == '0' ? '9' : x - 1);}char num_succ(char x) {return (x == '9' ? '0' : x + 1);}// 枚举 status 通过一次旋转得到的数字vector<string> get(string &status){vector<string> ret;for (int i = 0; i < 4; ++i) {char num=status[i];status[i]=num_prev(num);ret.push_back(status);status[i]=num_succ(num);ret.push_back(status);status[i] = num; //千万不能少因为我逐位变化第二位变化的时候第一位不能给他变了啊}return ret;}//进入主函数int openLock(vector<string>& deadends, string target) {unordered_set<string> dead(deadends.begin(), deadends.end()); //这个方式有点特别啊unordered_set<string> seen={"0000"};       //和第一种对比if(target=="0000")return 0;if(dead.count("0000"))return -1;queue<pair<string,int>> q;q.emplace("0000",0);while(!q.empty()){auto [status,step]=q.front();q.pop();for(auto && nextstatus:get(status)){if(!seen.count(nextstatus) && !dead.count(nextstatus)){if(nextstatus==target)return step+1;seen.insert(nextstatus);q.emplace(nextstatus,step+1);}}}return -1;}
};

说到这种搜索式的题目不得不提 滑动谜题,也是用bfs进行搜索,有点像上面的题目。感觉这两道题经常复习,有可能会出现在笔试中。  在这里插入图片描述
思路:
   注意到我们传入的参数step是当前已经完成的step,刚开始传入0,就是完成了0次,然后完成了一次后传入step+1;直接上代码:

class Solution {vector<vector<int>> neighbors = {{1, 3}, {0, 2, 4}, {1, 5}, {0, 4}, {1, 3, 5}, {2, 4}};
public:// 枚举 status 通过一次交换操作得到的状态vector<string> get (string& status) {vector<string> ret;int x = status.find('0');for (int y: neighbors[x]) {swap(status[x], status[y]);ret.push_back(status);swap(status[x], status[y]);}return ret;}  int slidingPuzzle(vector<vector<int>>& board) {string initial;for (int i = 0; i < 2; ++i) {for (int j = 0; j < 3; ++j) {initial += char(board[i][j] + '0');}}if (initial == "123450") {return 0;}queue<pair<string, int>> q;q.emplace(initial, 0);unordered_set<string> seen = {initial};while (!q.empty()) {auto [status, step] = q.front();q.pop();for (auto&& next_status: get(status)) {if (!seen.count(next_status)) {if (next_status == "123450") {return step + 1;}q.emplace(next_status, step + 1);seen.insert(move(next_status));}}}return -1;}
};

同样的,还是一道bfs题目:
在这里插入图片描述
在这里插入图片描述

class Solution {pair<int, int> id2rc(int id, int n) {int r = (id - 1) / n, c = (id - 1) % n;if (r % 2 == 1) {c = n - 1 - c;}return {n - 1 - r, c};}public:int snakesAndLadders(vector<vector<int>> &board) {int n = board.size();vector<int> vis(n * n + 1);queue<pair<int, int>> q;q.emplace(1, 0);while (!q.empty()) {auto p = q.front();q.pop();for (int i = 1; i <= 6; ++i) {int nxt = p.first + i;if (nxt > n * n) { // 超出边界break;}auto rc = id2rc(nxt, n); // 得到下一步的行列if (board[rc.first][rc.second] > 0) { // 存在蛇或梯子nxt = board[rc.first][rc.second]; //蛇或者梯子最终还是让他走后面那条路所以记录后面的。}if (nxt == n * n) { // 到达终点return p.second + 1;}if (!vis[nxt]) {vis[nxt] = true; //这个没问题,先来到这里的,肯定是最短路径,因为后面走的路都一样了!true完事!!!!!!q.emplace(nxt, p.second + 1); // 扩展新状态}}}return -1;}
};

—————————————————————————————————————————————
在这里插入图片描述
在这里插入图片描述
思路:
   这是和广度优先遍历干上了啊,这是和图能联系起来的问题,这种问题是一步步,所以是层序遍历。但是在层序遍历之前需要建立图关系。 有两种方法求解这个题目,官方题解是标准的图法,在B站看到一种比较好理解的思路。都给他记录下吧。上面的图是为了方便理解的。同样颜色的线代表移量公交车能走的区域。
   B站的思路:构建图只是为了方便思路,而不是利用纯粹图知识。首先建造一个哈希表用来存储对应站点邻接的公交车,比如1站点可以有2个公交车来操作,6站点只有一个公交车来操作。
   其次,建立一个关于公交车的set或者在这里是数组,来记录是否访问过某辆公交车。然后建立一个记录站点的队列和bus记录走过的公交车数量。初始值为0
   我们首先将初始站点加入队列,然后进入队列的while,注意到此时bus++,在当前队列中表明上车了。
   如何扩展队列呢?我们通过最开始建造的哈希表查找这个站点对应的公交车,1站点对应1 2两种公交车,我们可以从题目给的条件中获得对应公交车存在的站点。1 2 公交车存在的站点是1273,然后我们把站点扩展到队列中,下次以他们为中心搜索是否没走过的公交车。
   如果公交车走过了,我们就终止这边的扩展,因为同一种的公交车经过的站点我们已经在之前全部加入队列了。在加入的同时我们也判断了站点和目标站点是否相同了。
   注意到每次进入队列我们的bus数量就会+1,为了体现层序遍历,每次都要把队列清空!所以不用担心bus的重复,
   同一次能乘坐的公交车站点如果是走过的公交车他会continue,每个站点的价值在于是否能直到能扩展新的公交车,那么当能扩展新的公交车时,我们会标记公交车走过,然后查找对应公交车的新站点,判断,然后加入队列。表示再次搭了一轮车了。如果队列所有站点都无法扩展新的公交车,此时队列为空,然后返回-1了。

B站题解:

class Solution {
public:int numBusesToDestination(vector<vector<int>>& routes, int source, int target) {if(source==target)return 0;unordered_map<int,vector<int>>m;//某站点对应的公交车for(int i=0;i<routes.size();i++)for(const int stop: routes[i])m[stop].push_back(i);vector<int>ride(routes.size(),0);queue<int>q;q.emplace(source);int buses=0;while(!q.empty()){int size=q.size();buses++;for(int i=0;i<size;i++){   //注意到,前面不要在这里加q.size(),因为每次都是pop了!!int curr=q.front();q.pop();for(const int bus: m[curr]){ //找出站点对应的公交车if(ride[bus]) continue;ride[bus]=1;for(int stop:routes[bus]){//找出公交车对应的站点if(stop==target) return  buses;  q.emplace(stop);  //担心这里会不会重复增加进去呢 的确,重复了,但是没事接下来pop都做过的就会continue}}}}return -1;     }
};

官方题解:

class Solution {
public:int numBusesToDestination(vector<vector<int>>& routes, int source, int target) {if (source == target) {return 0;}int n = routes.size();vector<vector<int>> edge(n, vector<int>(n));unordered_map<int, vector<int>> rec;for (int i = 0; i < n; i++) {for (auto& site : routes[i]) {for (auto& j : rec[site]) {edge[i][j] = edge[j][i] = true; //每个公交车的连通情况 i是初始公交车,j是}rec[site].push_back(i);}}vector<int> dis(n, -1);queue<int> que;for (auto& site : rec[source]) {dis[site] = 1;que.push(site);}while (!que.empty()) {int x = que.front();que.pop();for (int y = 0; y < n; y++) {if (edge[x][y] && dis[y] == -1) {dis[y] = dis[x] + 1;que.push(y);}}}int ret = INT_MAX;for (auto& site : rec[target]) {if (dis[site] != -1) {ret = min(ret, dis[site]);}}return ret == INT_MAX ? -1 : ret;}
};

这篇关于bfs:打开转盘锁的最少次数(752)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/459251

相关文章

多源 BFS

例题一 解法(bfs)(多个源头的最短路问题) 算法思路: 对于求的最终结果,我们有两种⽅式: • 第⼀种⽅式:从每⼀个 1 开始,然后通过层序遍历找到离它最近的 0 。 这⼀种⽅式,我们会以所有的 1 起点,来⼀次层序遍历,势必会遍历到很多重复的点。并且如果 矩阵中只有⼀个 0 的话,每⼀次层序遍历都要遍历很多层,时间复

uniapp H5打开地图

manifest.json文件,源码视图找到H5添加下面内容 "h5" : {"sdkConfigs" : {"maps" : {"amap" : {"key" : "**********************","securityJsCode" : "****************************","serviceHost" : ""}}}} 高德开放平台 申请时选择(W

【Linux文件系统】被打开的文件与文件系统的文件之间的关联刨析总结

操作系统管理物理内存以及与外设磁盘硬件进行数据的交换 操作系统如何管理物理内存呢? 其实操作系统内核先对内存先描述再组织的!操作系统管理内存的基本单位是4KB,操作系统会为每一个4KB大小的物理内存块创建一个描述该4KB内存块的struct page结构体,该结构体存储着这4KB内存块的属性信息,通过管理struct page来对内存进行管理,page结构体的大小比较小,OS通常将它们组成一个

解除浏览器打开主页被锁定,修改方法

打开360安全卫士--》系统修复: 具体看如下截图就清楚 <script>window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"2","bdMiniList":false,"bdPic":"","bdStyle":"0","bdSize":"16"},"sh

在浏览器中打开预览sublime text当前所编辑文件的方法和快捷键设置

配置在Chrome,Firefox中打开 安装 SideBarEnhancements 然后通过ctrl + k, ctrl + b打开侧边栏,在侧边栏的文件中右击,找到 open width -> edit applications 然后在这里边设置firefox打开的方式。 application : 路径要修改为自己默认安装的路径。 [     {

vue dist文件打开index.html报Failed to load resource: net::ERR_FILE_NOT_FOUND

本地正常。打包好的dist文件打开index.html报Failed to load resource: net::ERR_FILE_NOT_FOUND 解决办法: 在webpack.prod.conf.js 中output添加参数publicPath:’./’ 在webpack.base.conf.js里 publicPath: process.env.NODE_ENV === ‘pro

BFS:解决多源最短路问题

文章目录 什么是多源最短路问题?1.矩阵2.飞地的数量3.地图的最高点4.地图分析总结 什么是多源最短路问题? 多源最短路问题(Multi-Source Shortest Path Problem,MSSP)是图论中的一个经典问题,它的目标是在给定图中找到从多个源点到所有其他顶点的最短路径。这个问题可以视为单源最短路问题(Single-Source Shortest Pa

【深海王国】小学生都能玩的单片机?零基础入门单片机Arduino带你打开嵌入式的大门!(8)

Hi٩(๑o๑)۶, 各位深海王国的同志们,早上下午晚上凌晨好呀~辛勤工作的你今天也辛苦啦 (o゜▽゜)o☆ 今天大都督继续为大家带来系列——小学生都能玩的单片机!带你一周内快速走进嵌入式的大门,let’s go! (8)软串口与SoftwareSerial库使用 在第六节中我们提到了,如果我们Arduino开发板的0、1号引脚接线了,即硬件串口被占用了,想给Arduino下载程序,就需要先