最小基因变化

LC433. 最小基因变化

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

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

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

另有一个基因库 bank 记录了所有有效的基因变化,只有基因库中的基因才是有效的基因序列。

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

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

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

思路:双向 BFS

  • 普通 BFS,从 start 开始,变化 start 的每个字符,同时判断变化好的 str 是否在 bank 中,时间复杂度过高。
  • 双向 BFS,start 和 end 都分别进行 BFS
  • 使用 queue 来存储 BFS 产生的新 str
  • 每次都先判断两个 queue 的 size,从最小的开始 BFS,生成新的 queue
  • 同时用一个 map 来记录是否被前、后 BFS 遍历过,如果都被遍历过,则直接输出当前的 step
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
class Solution {
public:
    int minMutation(string start, string end, vector<string>& bank) {
        unordered_map<string, int> mp;
        for (const auto & b : bank)
            mp[b] = 0;
        if (mp.count(end) == 0)
            return -1;
        queue<string> q1({start}), q2({end});
        int step = 0;
        const char table[4] = {'A', 'C', 'G', 'T'};
        // mp 记录遍历过的状态,1 表示从前遍历,2 表示从后遍历
        for (mp[start] |= 1, mp[end] |= 2; q1.size() && q2.size(); ++step) {
            // 根据 queue 的大小判断从哪 BFS
            bool first = q1.size() < q2.size();
            queue<string> &q= first ? q1 : q2;
            int flag = first ? 1 : 2;
            for (int n = q.size(); n--; q.pop()) {
                string& temp = q.front();
                // 等于 3,表示前后都遍历过,直接返回结果
                if (mp[temp] == 3)
                    return step;
                // BFS 更改结果
                for (int i = 0; i < temp.size(); i++) {
                    for (int j = 0; j < 4; j++) {
                        string s = temp;
                        if (s[i] == table[j])
                            continue;
                        s[i] = table[j];
                        if (mp.count(s) == 0 || mp[s] & flag)
                            continue;
                        mp[s] |= flag;
                        q.push(s);
                    }
                }
            }
        }
        return -1;
    }
};
updatedupdated2022-06-232022-06-23