图论,单源广搜BFS,附LeetCode.127.433.752解题注释

单源最短路问题,我们常常使用BFS来解决,但实际题目中,不会直接的把题目的解法直白的告诉你,常常是以一种不相关的表述,所以我们刷题锻炼的就是如何从不相关的题目描述中提取出来这个题目真正想要表达的。

这里博主列出LeetCode的三个题目,基本都是没有直观的描述图,并且解法进本相同,套用单源BFS,以下题解(包含注释),可作为大家学习板子和理解题目使用。

LeetCode433. 最小基因变化

从start 到 end,其中每次操作只允许一个位置发生一次编码变化,而且变化的编码是限定的(A T C G).我们使用BFS来枚举每一步之后产生的编码序列,并判断,当前步产生的编码是否已经到达end,或者当前编码是否合法。

class Solution {
public:    
    int minMutation(string start, string end, vector<string>& bank) {
        unordered_set<string> cnt;//合法编码,使用hash方便判断枚举的序列是否合法
        unordered_set<string> see;//路径节点访问标志,图中一个节点走过就不能走了。
        char keys[4] = {'A', 'C', 'G', 'T'}; //修改编码。
        for (auto & w : bank) {
            cnt.emplace(w);//初始化
        }
        if (start == end) {
            return 0;//剪枝
        }
        if (!cnt.count(end)) {
            return -1;//剪枝
        }
        queue<string> qu;//BFS 初始化队列
        qu.emplace(start);
        see.emplace(start);
        int step = 1;
        while (!qu.empty()) {
            int sz = qu.size();//很重要,每一步产生的所有符合要求的序列都会入队,要对每种入队的序列进行接下来的枚举。
            for (int i = 0; i < sz; i++) {
                string curr = qu.front();
                qu.pop();//取出合法序列
                for (int j = 0; j < 8; j++) {
                    for (int k = 0; k < 4; k++) {//进行枚举
                        if (keys[k] != curr[j]) {
                            string next = curr;
                            next[j] = keys[k];
                            // cout<<next<<endl;
                            if (!visited.count(next) && cnt.count(next)) {//没有访问过,并且符合bank条件
                                if (next == end) {
                                    return step; //找到了终点返回
                                }
                                // cout<<"--"<<next<<endl;
                                qu.emplace(next);//维护队列和see
                                see.emplace(next);
                            }
                        }
                    }
                }
            }
            step++;//每一步之后 step++
        }
        return -1; //全部枚举后没有找到,返回-1
    }
};

LeetCode127. 单词接龙

思想和上一个题目一模一样,处理的方式也相同,直接放上代码

class Solution {
public:
    int ladderLength(string beginWord, string endWord, vector<string>& wordList) {
        unordered_set<string> cnt;
        unordered_set<string> see;
        for(auto a : wordList)
        {
            cnt.emplace(a);
        }
        if(!cnt.count(endWord))
            return 0;
        queue<string> q;
        q.emplace(beginWord);
        see.emplace(beginWord);
        int step = 1;
        while(!q.empty())
        {
            int sz = q.size();
            for(int i = 0; i < sz; i++)
            {
                string cur = q.front();
                q.pop();
                for(int j = 0; j < beginWord.length(); j++)
                {
                    for(int k = 0; k < 26; k++)
                    {
                        char c = 'a' + k;
                        if(c != cur[j])
                        {
                            string next = cur;
                            next[j] = c;
                            if(!see.count(next) && cnt.count(next))
                            {
                                if(next == endWord)
                                    return ++step;
                                cout<<next<<endl;
                                q.emplace(next);
                                see.emplace(next);
                            }
                        }
                    }
                }
            }
            step++;
        }
        return 0;
    }
};

LeetCode752. 打开转盘锁

解法还是使用BFS,但是处理过程跟上面两个题目不同,这题是给了不能出现的数组,只需要在代码上判断上稍作修改。其中有一个读题的注意点:每次拨动一个转轮的一个数字(表示这个转轮的数字可以上下拨动,且只能拨动一次如 3可以变为1和4)所以在枚举的过程中处理一下,数字的拨动即可。

class Solution {
public:
    int openLock(vector<string>& deadends, string target) {
        unordered_set<string> cnt;
        unordered_set<string> see;
        for(auto a : deadends)
            cnt.emplace(a);
        if(target == "0000")
            return 0;
        if(cnt.count("0000"))
            return -1;
        queue<string> q;
        q.emplace("0000");
        see.emplace("0000");
        int step = 1;
        while(!q.empty())
        {
            int sz = q.size();
            for(int i = 0; i < sz; i++)
            {
                string cur = q.front();
                q.pop();
                for(int j = 0; j < 4; j++)
                {
                    for(int t = 0; t < 2; t++)
                    {
                        char k;
                        if(t == 0)
                            k = (cur[j] == '9' ? '0' : cur[j] + 1);
                        else
                            k = (cur[j] == '0' ? '9' : cur[j] - 1);
                        string next = cur;
                        next[j] = k;
                        if(!see.count(next) && !cnt.count(next))
                        {
                            if(next == target)
                                return step;
                            // cout<<next<<endl;
                            see.emplace(next);
                            q.emplace(next);
                        }    
                    }
                }
            }
            step++;
        }
        return -1;
    }
};

觉得文章有用,点个赞,点个收藏,支持一下

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BiuPsYao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值