BFS(广度优先搜索)优化技巧 — 双向遍历

BFS优化技巧 — 双向遍历

在之前我发过 动态规划框架动态规划的优化技巧 — 空间压缩,类似的,BFS框架 也有相应的优化技巧 双向遍历。从技巧的名字就可以看出,双向遍历指的就是从起点开始找终点的同时,也从终点开始找起点,一旦两个寻找过程出现交集,那么起点到终点的路径也就找出来了。

严谨一点表示:传统的 BFS 框架就是从起点开始向四周扩散,遇到终点时停止;而双向 BFS 则是从起点和终点同时开始扩散,当两边有交集的时候停止

同时扩散的话,效率肯定会更快一点,看下面两张图就会很明白了:

图的树形结构,【target】在最底层,按照传统BFS的遍历方式,需要从【start】开始,遍历所有节点,才能在最底层找到【target】,而双向遍历遍历树的一半时就出现了交集,也就是找到了最短距离。从这个例子是可以直观感受到,双向遍历是比传统传统单项遍历要好的。

但是,双向遍历的使用要有前提条件,也就是要提前知道【target】的位置,求【二叉树的最小深度】那道题就不适用,而【密码锁这道题】因为提前知道【target】的位置,所以可以使用双向遍历。

我在这给出使用双向遍历优化之后的代码:

 //将cur[j]向上拨一格
 string plusOne_(string cur, int j) {
     if (cur[j] == '9') cur[j] = '0';
     else cur[j] += 1;
     return cur;
 }
 ​
 //将cur[j]向下拨一格
 string minusOne_(string cur, int j) {
     if (cur[j] == '0') cur[j] = '9';
     else cur[j] -= 1;
     return cur;
 }
 ​
 //将问题抽象成图的问题,利用BFS算法解决问题
 int openLock(vector <string> &deadends, string target) {
     //需要先将死亡数字存储起来,为保证查找的时间复杂度为o(1),我们利用集合(哈希表)进行存储
     unordered_set <string> deads;
     for (string s: deadends) {
         deads.insert(s);
     }
     //记录穷举过的密码,防止走回头路
     unordered_set <string> q_start,q_target,visited;
     int step = 0;
     q_start.insert("0000");
     q_target.insert(target);
     //开始BFS遍历
     while (!q_start.empty() && !q_target.empty()) {
         //哈希表在遍历过程中不能修改,则新建一个哈希表temp存储扩散结果
         unordered_set <string> temp;
         
         //将q的所有节点进行扩散,先q_start,再q_target
         for(string s : q_start){
             if(deads.count(s) != 0) continue;
             if(q_target.count(s) != 0) return step; //说明出现了交集,直接返回结果
             visited.insert(s);
             
             //将每一个节点的未遍历节点加入temp中,作为下一层
             for(int j = 0; j < 4; j++){
                 string plusOne = plusOne_(s, j);
                 if(visited.count(plusOne) != 0) temp.insert(plusOne);   
                 string minusOne = minusOne_(s, j);
                 if(visited.count(plusOne) != 0) temp.insert(minusOne);  
             }
         }
         step++;
         q_start = q_target;
         q_target = temp;
     }
     //走到这里已经遍历完连通图的所有节点了,说明没有target
     return -1;
 }

这几天该准备我的期末考试了,所以每日分享的笔记篇幅会少一点,但是你们仍然可以借鉴与学习【手动狗头】。

  • 32
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值