题目:
碰到这种最少次数的问题,一下子就应该想到bfs,尤其是这种告诉终点的题目,还能用双向bfs进行优化。
解题代码–单向bfs:
就是正常的用队列实现层序遍历,每一层相当于走了一步,直到遍历到终点。
class Solution {
public:
int openLock(vector<string>& deadends, string target) {
unordered_set<string>visit;
visit.insert(deadends.begin(),deadends.end());
queue<string>q;
q.push("0000");
int step = 0;
while(!q.empty()){
int size = q.size();
for(int i=0;i<size;i++){
string cur = q.front();
q.pop();
if(cur == target)
return step;
//防止回头路
if(visit.count(cur))
continue;
//前面的比较进行过了,故加入已经访问的集合中
visit.emplace(cur);
//下面的操作是对下一层级的选择全盘入队
for(int j=0;j<4;j++){
string up = cur;
up[j] = up[j]=='9'?'0':up[j]+1;
if(!visit.count(up))
q.push(up);
string down = cur;
down[j] = down[j]=='0'?'9':down[j]-1;
if(!visit.count(down))
q.push(down);
}
}
step++;
}
return -1;
}
};
双向bfs:
双向bfs一般使用set,因为双向bfs不需要判断是否为target,只需要判断我们遍历到的元素是否与上一个交替遍历的集合有相同的元素即可。同样也需要visit进行标记防止走回头路。但是注意更新visit的位置。
class Solution {
public:
int openLock(vector<string>& deadends, string target) {
//visit防止走回头路,同时其中也包含死亡数字
unordered_set<string>visit;
visit.insert(deadends.begin(),deadends.end());
string start = "0000";
unordered_set<string>q1;
unordered_set<string>q2;
q1.emplace(start);
q2.emplace(target);
int step = 0;
while(!q1.empty()&&!q2.empty()){
unordered_set<string>temp;
for(string cur:q1){
if(q2.count(cur))
return step;
//碰到死亡数字,跳过,碰到已经遍历过的数字跳过
if(visit.count(cur))
continue;
//对每个没有遍历过的加入到visit
visit.emplace(cur);
//向八个方向拨动
for(int j=0;j<4;j++){
string up = cur;
up[j]=up[j]=='9'?'0':up[j]+1;
if(!visit.count(up))
temp.emplace(up);
string down = cur;
down[j]=down[j]=='0'?'9':down[j]-1;
if(!visit.count(down))
temp.emplace(down);
}
}
step++;
//轮流扩散
q1 = q2;
q2 = temp;
}
return -1;
}
};