如何快速写好bfs?

Posted C_YCBX Py_YYDS

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何快速写好bfs?相关的知识,希望对你有一定的参考价值。

如何快速写好bfs?

为什么说是如何快速写好呢?
我认为于大多数人而言,懂得了基本的bfs模板,那么写好这个大概的框架肯定是不在话下,但就是有那么一段逻辑可能会格格不入。
那段逻辑就是扩散时候的各种操作逻辑。

  • 如何解决?
  1. 弄清扩散的目的是什么?扩散的目的是为了找到终点,如果该轮扩散都未找到终点,那么扩散就为你提供了后续的起点,也就是说扩散的最终目的还是为了找到终点。中间未找到终点的操作无非就是入队形成下一层结点,以及入visit防止走回头路。
  2. 把较为割裂的逻辑与主逻辑分离。这种方式运用于很多的大工程上,于一些复杂一点的bfs,我们也应该用该方式分离逻辑,主逻辑是遍历队列进行下层扩散,而我们继续把扩散这一过程给分离,由上一点所说,将扩散过程分解为一个服务于寻找终点的函数,而它扩散后都会做完两个操作:入队(对于双向bfs则是入Set)和入visit

例题练手

题目

在这里插入图片描述

双向bfs主逻辑

//双向bfs,两头轮流遍历
            unordered_set<string>q1;
            unordered_set<string>q2;
            unordered_set<string>visit;
            unordered_set<string>found;
            int wordLen;
    int ladderLength(string beginWord, string endWord, vector<string>& wordList) {
        //构建结果能否被找到的图      
        for(string& t:wordList)found.insert(t);
        //一旦endWord不存在其中,则无论如何都无答案
        if(!found.count(endWord))return 0;
        //初始化数据
        q1.insert(beginWord);q2.insert(endWord);
        visit.insert(beginWord);visit.insert(endWord);
        int step = 1;
        wordLen = beginWord.size();
        
        while(!q1.empty()&&!q2.empty()){
            unordered_set<string>temp;
            //开始扩散寻求结果,直接封装成一个check函数,防止思维一时半会儿跟不上
            for(auto s:q1){
            //扩散找到了结果返回
               if(check(s,temp))
                    return step+1;
            }
            //未找到结果,增加step,换q2遍历
            step++;
            q1 = q2;
            q2 = temp;
        }
        return 0;
    }

双向bfs扩散逻辑

//对每个单词位进行枚举,并对temp进行更新(如果是单向则是操作一个队列入队即可)
bool check(string& s,unordered_set<string>&temp){ 
        for(int i=0;i<wordLen;i++){
            char t = s[i];
            for(char j='a';j<='z';j++){
                if(t==j)continue;
                    s[i] = j;
                if(found.count(s)){
                    //扩散找到答案
                    if(q2.count(s))
                        return true;
                    //未找到答案更新该层结果到temp
                    if(!visit.count(s)){
                        visit.insert(s);
                        temp.insert(s);
                    }
                }
            }
        s[i] = t;
        }
        //此层扩散并未找到答案
    return false;
    }

整段代码提交后的效率

在这里插入图片描述

class Solution {
public:
//双向bfs,两头轮流遍历
            unordered_set<string>q1;
            unordered_set<string>q2;
            unordered_set<string>visit;
            unordered_set<string>found;
            int wordLen;
    int ladderLength(string beginWord, string endWord, vector<string>& wordList) {
        //构建能否被找到的图      
        for(string& t:wordList)found.insert(t);
        //一旦endWord不存在其中,则无论如何都无答案
        if(!found.count(endWord))return 0;
        //初始化数据
        q1.insert(beginWord);q2.insert(endWord);
        visit.insert(beginWord);visit.insert(endWord);
        int step = 1;
        wordLen = beginWord.size();
        //开始双向bfs扩散
        while(!q1.empty()&&!q2.empty()){
            unordered_set<string>temp;
            //开始扩散寻求结果,直接封装成一个check函数,防止思维一时半会儿跟不上
            for(auto s:q1){
               if(check(s,temp))
                    return step+1;
            }
            step++;
            q1 = q2;
            q2 = temp;
        }
        return 0;
    }
private:
    bool check(string& s,unordered_set<string>&temp){ 
        for(int i=0;i<wordLen;i++){
            char t = s[i];
            for(char j='a';j<='z';j++){
                if(t==j)continue;
                    s[i] = j;
                if(found.count(s)){
                    //扩散找到答案
                    if(q2.count(s))
                        return true;
                    //未找到答案保存此层扩散结果(不含重复)
                    if(!visit.count(s)){
                        visit.insert(s);
                        temp.insert(s);
                    }
                }
            }
        s[i] = t;
        }
        //此层扩散并未找到答案
    return false;
    }
};

以上是关于如何快速写好bfs?的主要内容,如果未能解决你的问题,请参考以下文章

前端开发工具vscode如何快速生成代码片段

前端开发工具vscode如何快速生成代码片段

如何使用sublime代码片段快速输入PHP头部版本声明

代码片段如何使用CSS来快速定义多彩光标

如何写好业务代码

c#代码片段快速构建代码