bfs(单向和双向)求解最短路径问题(也可理解为最小次数)--以开锁问题为例子

题目:

在这里插入图片描述

碰到这种最少次数的问题,一下子就应该想到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;  
        }
};
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值