433. 最小基因变化
方法:BFS
class Solution {
public:
// 每次在字符串数组中搜索,把与队首仅一位不相同的字符串入队。已经访问过的字符串从原数组中删除,节省记录是否访问的数组的空间
int minMutation(string startGene, string endGene, vector<string>& bank) {
// 走的步数,广度优先搜索按照层次遍历,找到的时候次数必然是最少的
int step = 0;
// BFS用到的队列,队列中始终保存距上一队首的字符串仅有一位不同的字符串
queue<string> stringQueue;
stringQueue.push(startGene);
while(!stringQueue.empty()){
// 距上一队首的字符串仅有一位不同的字符串的数量
int levelSize= stringQueue.size();
for(int i = 0; i < levelSize; i++){
// 注意是在循环中取队首的元素,把有一位不一样的全比较一遍,看是否有endGene
string queueHead = stringQueue.front();
stringQueue.pop();
// 有endGene的话就退出,因为是BFS,此时的step就是最少的次数
if(queueHead == endGene){
return step;
}
// 否则,对每一个队首元素检查基因库中只有一位不一样的元素入队,并且将入队的字符串从bank中删掉
auto gene = bank.begin();
while(gene != bank.end()){
int diff = 0;
for (int i = 0; i < queueHead.size(); i++) {
if ((*gene)[i] != queueHead[i]){
diff++;
}
}
// 如果和队首元素只有一位不一样,就入队,并且从字符串数组中删掉;
// 注意删除的写法,erase的参数时迭代器,这里会涉及到迭代器的失效问题
if (diff == 1){
stringQueue.push(*gene);
gene = bank.erase(gene); // 这里的缺点是字符串数组传的是引用,会直接对原数据进行修改,为保证数据安全性,也可以先在程序开始时复制一份。
}
else{
gene++;
}
}
}
// 相当于树的每一层++,因此找到endGene字符串的时候必然是最小的步数
step++;
}
return -1;
}
};
class Solution {
public:
// 每次把与队首仅一位不相同且未被访问过的字符串入队,与上边判断仅一位不同的方式有点区别,并且用set记录字符串是否被访问
int minMutation(string startGene, string endGene, vector<string>& bank) {
// 保存所有已经遇到过的字符串,用set保存,后边查找是否有某个字符串时速度更快
unordered_set<string> bank_set(bank.begin(), bank.end());
unordered_set<char> charSet({'A', 'C', 'G', 'T'});
// 记录访问过的字符串,防止重复访问
unordered_set<string> visitedString;
visitedString.insert(startGene);
// BFS用到的队列,队列中始终保存距上一队首的字符串仅有一位不同的字符串
queue<string> stringQueue;
stringQueue.push(startGene);
// 走的步数,广度优先搜索找到的时候次数必然是最少的
int step = 0;
while(!stringQueue.empty()){
// 距上一队首的字符串仅有一位不同的字符串的数量
int queueSize = stringQueue.size();
for(int i = 0; i < queueSize; i++){
// 注意是在循环中取队首的元素,把有一位不一样的全比较一遍,看是否有endGene
string queueHead = stringQueue.front();
stringQueue.pop();
// 有endGene的话就退出,因为是BFS,此时的step就是最少的次数
if(queueHead == endGene){
return step;
}
// 否则,对每一个队首元素检查基因库中只有一位不一样的元素入队
for(auto gene : charSet){
for(int j = 0; j < queueHead.size(); j++){
// 因为queueHead字符串在整个双重循环的过程中都要用到,所以不能直接修改queueHead
string temp = queueHead;
temp[j] = gene;
// 如果基因库中有这个仅一位变异的基因,并且未曾访问过,就入队
if(bank_set.count(temp) && !visitedString.count(temp)){
stringQueue.push(temp);
visitedString.insert(temp);
}
}
}
}
// 相当于树的每一层++,因此找到endGene字符串的时候必然是最小的步数
step++;
}
return -1;
}
};