你有一个带有四个圆形拨轮的转盘锁。每个拨轮都有10个数字: '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' 。每个拨轮可以自由旋转:例如把 '9' 变为 '0','0' 变为 '9' 。每次旋转都只能旋转一个拨轮的一位数字。
锁的初始数字为 '0000' ,一个代表四个拨轮的数字的字符串。
列表 deadends 包含了一组死亡数字,一旦拨轮的数字和列表里的任何一个元素相同,这个锁将会被永久锁定,无法再被旋转。
字符串 target 代表可以解锁的数字,你需要给出解锁需要的最小旋转次数,如果无论如何不能解锁,返回 -1 。
示例 1:
输入:deadends = ["0201","0101","0102","1212","2002"], target = "0202"
输出:6
解释:
可能的移动序列为 "0000" -> "1000" -> "1100" -> "1200" -> "1201" -> "1202" -> "0202"。
注意 "0000" -> "0001" -> "0002" -> "0102" -> "0202" 这样的序列是不能解锁的,
因为当拨动到 "0102" 时这个锁就会被锁定。
示例 2:
输入: deadends = ["8888"], target = "0009"
输出:1
解释:把最后一位反向旋转一次即可 "0000" -> "0009"。
示例 3:
输入: deadends = ["8887","8889","8878","8898","8788","8988","7888","9888"], target = "8888"
输出:-1
解释:无法旋转到目标数字且不被锁定。
BFS(在一幅「图」中找到从起点 start 到终点 target 的最近距离)
- class Solution {
- public:
- int openLock(vector
& deadends, string target) { - int step=0;
- unordered_set
deadSet;// 记录需要跳过的死亡数字 - unordered_set
visited;//记录已经穷举过的密码,防止走回头路 - for(string s:deadends)
- {
- deadSet.insert(s);
- }
- queue
q; - q.push("0000");
- visited.insert("0000");
- while(!q.empty())
- {
- int size=q.size();
- /* 将当前队列中的所有节点向周围扩散 */
- for(int i=0;i
- {
- string cur=q.front();
- q.pop();
- //如果是死亡数字,就跳过这种情况
- if(deadSet.count(cur))
- {
- continue;
- }
- //如果等于target,就返回操作步数
- if(!cur.compare(target))
- {
- return step;
- }
- /* 将一个节点cur的未遍历相邻节点加入队列 */
- /*相邻结点有八个,四个位置,每个位置有拨上拨下两种选择*/
- for(int j=0;j<4;j++)
- {
- //朝上拨
- string s1=cur;
- if(s1[j]=='9')
- s1[j]='0';
- else
- s1[j]+=1;
- if(!visited.count(s1))//未遍历过,就加入队列
- {
- q.push(s1);
- visited.insert(s1);
- }
-
- //朝下拨
- string s2=cur;
- if(s2[j]=='0')
- s2[j]='9';
- else
- s2[j]-=1;
- if(!visited.count(s2))//未遍历过,就加入队列
- {
- q.push(s2);
- visited.insert(s2);
- }
- }
- }
- /* 在这里增加步数 */
- step++;
- }
- //如果穷举完都没找到目标密码,那就是找不到了
- return -1;
- }
- };
773.滑动谜题
在一个 2 x 3 的板上(board)有 5 块砖瓦,用数字 1~5 来表示, 以及一块空缺用 0 来表示。一次 移动 定义为选择 0 与一个相邻的数字(上下左右)进行交换.
最终当板 board 的结果是 [[1,2,3],[4,5,0]] 谜板被解开。
给出一个谜板的初始状态 board ,返回最少可以通过多少次移动解开谜板,如果不能解开谜板,则返回 -1 。
示例 1:
输入:board = [[1,2,3],[4,0,5]]
输出:1
解释:交换 0 和 5 ,1 步完成

思路:BFS
如何用 BFS 算法秒杀各种智力题 :: labuladong的算法小抄 (gitee.io)
用字符串来描述board当前的状态,要把board从start状态以最小的步数转换成target=“123450”状态。 从状态cur向外扩散,即是‘ 0 ’与它周围的板块进行交换,我们通过neighbors数组来描述相邻关系。
vectorint>> neighbors={{1,3},{0,2,4},{1,5},{0,4},{1,3,5},{2,4}};

- class Solution {
- public:
- void swap(string& s,int i,int j)
- {
- char temp;
- temp=s[i];
- s[i]=s[j];
- s[j]=temp;
- }
- int slidingPuzzle(vector
int >>& board) { - string start;
- start.resize(6);
- for(int i=0;i<2;i++)//构建初始状态start
- {
- for(int j=0;j<3;j++)
- {
- start[i*3+j]=board[i][j]+'0';//注意类型转换,start中存的是字符,board中存的是数字
- }
- }
- //用来描述相邻关系的neighbors数组
- vector
int>> neighbors={{1,3},{0,2,4},{1,5},{0,4},{1,3,5},{2,4}}; - int step=0;
- string target="123450";//目标状态
- queue
q; - unordered_set
visited;//防止走回头路,陷入死循环 - q.push(start);
- visited.insert(start);
- while(!q.empty())
- {
- int size=q.size();
- for(int i=0;i
- {
- string cur=q.front();
- if(!cur.compare(target))
- {
- return step;
- }
- int index=cur.find('0');//找到cur中'0'对应的下标
- q.pop();
- //从和'0'相邻的字符开始扩展(和'0'进行交换)
- for(int neighbor:neighbors[index])
- {
- string tmp=cur;
- swap(tmp,neighbor,index);
- //防止走回头路
- if(!visited.count(tmp))
- {
- q.push(tmp);
- visited.insert(tmp);
- }
- }
- }
- step++;
- }
- return -1;
- }
- };
对于某些非负整数 k ,如果交换 s1 中两个字母的位置恰好 k 次,能够使结果字符串等于 s2 ,则认为字符串 s1 和 s2 的 相似度为 k 。
给你两个字母异位词 s1 和 s2 ,返回 s1 和 s2 的相似度 k 的最小值。
示例 1:
输入:s1 = "ab", s2 = "ba"
输出:1
示例 2:
输入:s1 = "abc", s2 = "bca"
输出:2
思路:BFS,求最小步数
从当前位置往后面找该位置正确的字母,交换,直至完全等于s2。
这里要注意剪枝逻辑:
一、如果交换完后的情况在之前出现过,再次出现的话就不用继续跑了(因为1、如果都是本层的情况,那么跑一种就够了 2、如果是上层的情况,那么现在这种肯定比上次那种步数多,也不用再跑了)。( unordered_set < string > visited )
二、判断要交换的那个字母,现在所在位置是否已经是正确的,如果本来就是正确的就不用换过来了。(s [ j ] ! = s2 [ j ] )
- //求最小值,所以使用BFS算法
- class Solution {
- public:
- int kSimilarity(string s1, string s2) {
- queue
int>> q; - unordered_set
visited;//防止重复搜索字符串 - q.emplace(s1,0);
- int step=0;
- while(!q.empty())
- {
- int size=q.size();
- for(int i=0;i
- {
- pair
int> cur=q.front(); - int index=cur.second;
- string s=cur.first;
- if(s==s2)
- return step;
- q.pop();
- while(index
size()&&s[index]==s2[index]) - {
- index++;
- }
- //选择列表————s[index..]中的任意一个字符
- for(int j=index;j
size();j++) - {
- //剪枝,选择s[j]!=s2[j]的字符
- if(s[j]==s2[index]&&s[j]!=s2[j])
- {
- swap(s[j],s[index]);
- if(!visited.count(s))//如果交换后的结果之前没有出现过
- {
- visited.insert(s);//记录到备忘录里
- q.emplace(s,index+1);//加入队列
- }
- //再交换回来,保持for循环中s不变,因为for循环中的选项都是由s引出的
- swap(s[j],s[index]);
- }
- }
- }
- //操作步数加一
- step++;
- }
- return 0;
- }
- };
-
相关阅读:
什么是大数据测试?有哪些类型?应该怎么测?
图解AVLTree
AQS(AbstractQueuedSynchronizer)框架之ReentrantLock
【同花顺】同花顺解题
Jtti:Ubuntu下如何创建XFS文件系统的LVM
HarmonyOS ArkTSTabs组件的使用(六)
嵌入式面试3(C++相关)
排序算法之---归并排序
使用Specification与Example方式实现动态条件查询案例
测试覆盖率设计与实践
-
原文地址:https://blog.csdn.net/weixin_50437588/article/details/126714086