433、最小基因变化——BFS

一、题目描述

433、最小基因变化

基因序列可以表示为一条由 8 个字符组成的字符串,其中每个字符都是 'A''C''G''T' 之一。
假设我们需要调查从基因序列 start 变为 end 所发生的基因变化。一次基因变化就意味着这个基因序列中的一个字符发生了变化。
    ● 例如,"AACCGGTT" --> "AACCGGTA" 就是一次基因变化。
另有一个基因库 bank 记录了所有有效的基因变化,只有基因库中的基因才是有效的基因序列。
给你两个基因序列 startend ,以及一个基因库 bank ,请你找出并返回能够使 start 变化为 end 所需的最少变化次数。如果无法完成此基因变化,返回 -1
注意:起始基因序列 start 默认是有效的,但是它并不一定会出现在基因库中。

示例:
输入start = "AACCGGTT", end = "AAACGGTA",
bank = ["AACCGGTA","AACCGCTA","AAACGGTA"]
输出2

二、分析与思路

    今天的每日一题是广度优先搜索的知识,但是对这些知识点并不熟悉,只是知道要用到 队列 的知识,因此又是抄官方题解、理解官方题解的一天;

    变化规则:给定一个字符串 start ,每次只能改变一个字符得到一个新的字符串 next ;这个最字符串只有在字符串库 bank 里面才算一个合法的字符串;并且每个变化字符只能 A’, ‘C’, ‘G’, ‘T’ 中进行选择;这里的字符串也就是题目中提到的基因序列。

根据以上变化规则,我们可以进行尝试所有合法的基因变化,并找到最小的变化次数;
    (1)如果 startend 相等,此时直接返回 0;如果最终的基因序列不在 bank 中,则此时按照题意要求,无法生成,直接返回 -1
    (2)首先我们将可能变换的基因 s 从队列中取出,按照上述的变换规则,尝试所有可能的变化后的基因,比如一个 AACCGGTA \texttt{AACCGGTA} AACCGGTA,我们依次尝试改变基因 s 的一个字符,并尝试所有可能的基因变化序列 s 0 , s 1 , s 2 , ⋯   , s i , ⋯   , s 23 s_0, s_1, s_2, \cdots, s_i, \cdots, s_{23} s0,s1,s2,,si,,s23,变化一次最多可能会生成 3 × 8 = 24 3 \times8=24 3×8=24 种不同的基因序列;
    (3)我们需要检测当前生成的基因序列的合法性 s i s_i si,首先利用哈希表检测 s i s_i si 是否在数组 bank \textit{bank} bank 中,如果是则认为该基因合法,否则把非法直接丢弃;其次我们还需要用哈希表记录已经遍历过的基因序列,如果该基因序列已经遍历过,则此时直接跳过;如果是合法且未遍历过的基因序列,那么我们将其加入到队列中;
    (4)如果当前变换后的基因序列与 end \textit{end} end 相等,此时我们直接返回最小的变化次数即可;如果队列中所有的元素都已经遍历完成还无法变成 end \textit{end} end ,此时无法实现目标变化,返回 − 1 -1 1

三、代码实现

class Solution {
public:
    int minMutation(string start, string end, vector<string>& bank) {
        unordered_set<string> cnt, visited;
        char keys[4] = {'A', 'T', 'C', 'G'};

        for(auto &str : bank){
            cnt.insert(str);
        }
        // 去除一些特殊情况
        if(start == end){					// (1)
            return 0;
        }
        if(cnt.count(end) == 0){
            return -1;
        }
        queue<string> q;
        q.push(start);
        visited.insert(start);
        int step = 1;

        while(!q.empty()){
            int sz = q.size();
            int i, j, k;
            for(i = 0; i < sz; ++i){		 // (2)
                string now = q.front();
                q.pop();
                for(j = 0; j < 8; ++j){
                    for(k = 0; k < 4; ++k){
                        if(keys[k] != now[j]){
                            string next = now;
                            next[j] = keys[k];
                            if(!visited.count(next) && cnt.count(next)){  // (3)
                                if(next == end){						  // (4)
                                    return step;
                                }
                                q.push(next);
                                visited.insert(next);
                            }
                        }
                    }
                }
            }
            ++step;
        }
        return -1;
    }
};

四、总结

    (1)广度优先搜索,一般用来求解 树的层序遍历问题、最短路问题、连通性问题、拓扑排序,这也是接下来的学习重点。后序继续更新;
    (2) set \texttt{set} set 的插入操作是 emplace() 或者 insert() 。注意对于 set \texttt{set} set 中的 count() 命令的使用。

五、参考资料

1、最小基因变化-官方题解;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

wang_nn

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

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

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

打赏作者

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

抵扣说明:

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

余额充值