每天一道leetcode:433. 最小基因变化(图论&中等&广度优先遍历)

今日份题目:

基因序列可以表示为一条由 8 个字符组成的字符串,其中每个字符都是 'A'、'C'、'G' 和 'T' 之一。

假设我们需要调查从基因序列 start 变为 end 所发生的基因变化。一次基因变化就意味着这个基因序列中的一个字符发生了变化。

  • 例如,"AACCGGTT" --> "AACCGGTA" 就是一次基因变化。

另有一个基因库 bank 记录了所有有效的基因变化,只有基因库中的基因才是有效的基因序列。(变化后的基因必须位于基因库 bank 中)

给你两个基因序列 start 和 end ,以及一个基因库 bank ,请你找出并返回能够使 start 变化为 end 所需的最少变化次数。如果无法完成此基因变化,返回 -1 。

注意:起始基因序列 start 默认是有效的,但是它并不一定会出现在基因库中。

示例1

复制代码
输入:start = "AACCGGTT", end = "AACCGGTA", bank = ["AACCGGTA"]
输出:1

示例2

复制代码
输入:start = "AACCGGTT", end = "AAACGGTA", bank = ["AACCGGTA","AACCGCTA","AAACGGTA"]
输出:2

示例3

复制代码
输入:start = "AAAAACCC", end = "AACCCCCC", bank = ["AAAACCCC","AAACCCCC","AACCCCCC"]
输出:3

提示

  • start.length == 8

  • end.length == 8

  • 0 <= bank.length <= 10

  • bank[i].length == 8

  • start、end 和 bank[i] 仅由字符 ['A', 'C', 'G', 'T'] 组成

题目思路

这道题广度优先的思路有点暴力搜索的意思,就是遍历所有的可能组合,然后找到最后的结果组合,找不到就返回-1,找得到就返回步数。具体来说,我们需要遍历所有8个位置的所有4个字母的组合,如果某个组合未被遍历过并且能在字典中找到,那么就放入bfs队列中,否则跳过,每层bfs结束step加一,直到找到最后结果。

注意:unodered_set插入使用emplace;使用visited集合标记遍历过的组合;第一个找到的就是最小的step,因为一起加加,所以第一个满足时就是结果了。

代码

cpp 复制代码
class Solution 
{
public:    
    int minMutation(string start, string end, vector<string>& bank) 
    {
        unordered_set<string> dict; //存放字典信息
        unordered_set<string> visited;
        char chara[4]={'A','C','G','T'};        
        for(auto &b:bank) 
        {
            dict.emplace(b);
        }
        if(start==end) //剪枝,未变化
        {
            return 0;
        }
        if(!dict.count(end)) //如果变换后的组合不在字典中,那么无法实现变化,返回-1
        {
            return -1;
        }
        queue<string> p;
        p.push(start);
        visited.emplace(start);
        int step=1;
        //bfs
        while(!p.empty()) 
        {
            int n=p.size();
            for(int i=0;i<n;i++) 
            {
                string curr=p.front();
                p.pop();
                //遍历每位的所有可能的字母情况
                for(int j=0;j<8;j++) //遍历序列的8个位置
                {
                    for(int k=0;k<4;k++) //遍历4种字母
                    {
                        if(chara[k]!=curr[j]) //当前不是这个字母
                        {
                            string next=curr;
                            next[j]=chara[k];//在当前组合的基础上,将这个位置的字母改为当前字母
                            if(!visited.count(next)&&dict.count(next)) 
                            {
                                //可以加入的条件:在字典中能找到并且没有被遍历过
                                if(next==end) //找到最后的了,返回步数
                                {
                                    return step;
                                }
                                //还未找到最后
                                p.push(next);
                                visited.emplace(next);
                            }
                        }
                    }
                }
            }
            step++;//每完成一层就加一,与上个题一样
        }
        return -1;
    }
};

提交结果

欢迎大家在评论区讨论,如有不懂的部分,欢迎在评论区留言!

更新不易,宝子们点个赞支持下,谢谢!

每天一道leetcode,大家一起在评论区打卡呀!

相关推荐
I_belong_to_jesus8 小时前
C++关于分支预测的优化1
开发语言·c++·算法
Rabitebla9 小时前
【Linux】进程控制(十二) 自定义 Shell(二):内建命令与进程工作目录管理
linux·c++·笔记·学习·bash
码客-ygluu15 小时前
一个通用游戏数据服务器
c++·架构
another heaven15 小时前
【C/C++ Ranges 是零开销抽象吗?拆开管道、惰性求值和编译期膨胀】
c语言·开发语言·c++
Code_Solitude15 小时前
C语言动态内存 + 柔性数组 + 数组名退化
c语言·算法·柔性数组
上海潭龙东海科技有限公司15 小时前
客运站管控之动态孪生技术方案(新增一屏管控模块
数据仓库·人工智能·算法·重构·动态规划
文丑颜不良啊16 小时前
LeetCode2821~2840题目解析
java·leetcode
YLCHUP17 小时前
【思维&图论建模】题解:债权(debt)_图论_建模_思路转化_思维题目_C++算法竞赛
c++·笔记·算法·数学建模·贪心算法·深度优先·图论
xiaoye-duck17 小时前
《C++ 项目:手写大模型接入 SDK》会话模块整合:内存 SessionManager 与 DataManager 持久化联动
开发语言·数据库·c++·语言模型