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;
}
};
|