【LeetCode752】打开转盘锁(BFS)
原创
©著作权归作者所有:来自51CTO博客作者wx62cea850b9e28的原创作品,请联系作者获取转载授权,否则将追究法律责任
一、题目
中等题。
二、思路
每个节点有8个孩子节点,如题目给的第二个测试用例,start=0000时,4个位置分别可以向上转or向下转,得到1000、9000、0100、0900等8种情况。即这是一棵八叉树。即求解从start数字到target的最短路径。为了找到最小旋转次次数,利用BFS逐层查找,遇到target则返回树高度(层数)。
需要关注两个点:
(1)防止走回头路,如从0000到1000,之后不能回到0000,不然就死循环了。所以需要借助哈希表。
(2)需要跳过died number,这也是关键。
有几个问题:
(1)为什么使用bfs。
初始化就是从0000开始,向周围8个结点发散,从无向图中来看就是从核心向周围不断扩散,同时记录扩散的圈数作为旋转次数,如果遇到deadends直接跳过,或者达到target直接返回即可。这种操作方式十分符合优化的BFS。
(2)为了方便,甚至可以不用哈希表,而是直接使用set集合(装dead num和已经遍历过的数字),即如果set有当前情况的数字或者dead num则跳过。
(3)需要将char类型转为数字后,再转为char类型,利用ASCII码做减法,用C++的c_str()
和to_string
也可以(但是用法不太好记)。
BFS使用队列,伪代码如下:
void BFS(int s){
queue<int>q;
q.push(s);
while(!q.empty()){
取出队首元素top;
访问队首元素top;
将队首元素出队pop;
将top的下一层结点中未曾入队的结点全部入队,并设置为已入队;
}
}
三、代码
class Solution {
public:
int openLock(vector<string>& deadends, string target) {
queue<string> q;
//visited存储不阔能入队的节点,包括deadends和已访问过的节点
unordered_set<string> visited;
visited.insert(deadends.begin(), deadends.end());
if(visited.count("0000")){
return -1;
}
//初始化哈希表
int ans = 0;
q.push("0000");
while(!q.empty()){
int length = q.size();
for(int i = 0; i < length; i++){
string curr = q.front();
q.pop();
//找到目标元素,直接返回ans
if(curr == target){
return ans;
}
//处理curr周围的8个孩子节点
for(int j = 0; j < 4; j++){
//自增1和自减1
for(int k = -1; k < 2; k += 2){
char a = (curr[j] -'0' + k + 10) % 10 + '0';
string newStr = curr;
newStr[j] = a;
//若哈希集合中找不到此状态,则加入哈希表,并入队
if(!visited.count(newStr)){
//入队,bfs
q.push(newStr);
visited.insert(newStr);//加入哈希集合
}
}
}
}
//本层队列中元素处理完成,到达下一层
ans++;
}
return -1;
}
};