问题描述
用不含重复字母的字符串表示一段基因序列。如果一段基因序列可以通过以下任一操作得到另一个基因序列,则认为这两段基因是同源的(或者说有血缘关系):
- 增加一个字母
- 删除一个字母
- 改变一个字母
给定若干个基因序列,求一共有多少种不同的血缘关系(即连通分量的数量)。
输入规范
- 输入仅包含小写字母
- 基因序列的总数量不超过 10,000
示例
示例 1
输入: ["a", "b", "ab", "cde"]
输出: 2
解释:
- "a"、"b" 和 "ab" 互为同源(可通过增加或删除一个字母相互转换)
- "cde" 与其他序列不同源
- 因此共有 2 个血缘组
示例 2
输入: ["a", "ab", "abc", "ba"]
输出: 1
解释:
- 所有序列都在同一个连通分量中(可以通过一系列操作相互转换)
- 因此共有 1 个血缘组
cpp
#include <iostream>
#include <string>
#include <vector>
#include <unordered_set>
#include <unordered_map>
#include <algorithm>
using namespace std;
class UnionFind {
private:
unordered_map<string, string> parent;
public:
UnionFind(const vector<string>& sequences){
for(const string& s : sequences){
parent[s] = s;
}
}
string find(const string& s){
if(parent[s] != s){
parent[s] = find(parent[s]);
}
return parent[s];
}
void unionSets(const string& s1, const string& s2){
string root1 = find(s1);
string root2 = find(s2);
if(root1 != root2){
parent[root1] = root2;
}
}
int countRoots(){
unordered_set<string> roots;
for(const auto& entry : parent){
roots.insert(find(entry.first));
}
return roots.size();
}
};
int numHomologyGroups(vector<string>& sequences){
unordered_set<string> seqSet(sequences.begin(), sequences.end());
UnionFind uf(sequences);
for(const string& s : sequences){
unordered_set<char> chars(s.begin(), s.end());
// 增加一个字符
for(char c = 'a'; c < 'z'; ++c){
if(chars.find(c) == chars.end()){
for(int i = 0; i <= s.size(); ++i){
string newS = s.substr(0, i) + c + s.substr(i);
if(seqSet.find(newS) != seqSet.end()){
uf.unionSets(s, newS);
}
}
}
}
// Delete operation
for (size_t i = 0; i < s.size(); ++i) {
string newS = s.substr(0, i) + s.substr(i + 1);
if (seqSet.find(newS) != seqSet.end()) {
uf.unionSets(s, newS);
}
}
// Change operation
for (size_t i = 0; i < s.size(); ++i) {
char originalChar = s[i];
for (char c = 'a'; c <= 'z'; ++c) {
if (c != originalChar && chars.find(c) == chars.end()) {
string newS = s.substr(0, i) + c + s.substr(i + 1);
if (seqSet.find(newS) != seqSet.end()) {
uf.unionSets(s, newS);
}
}
}
}
}
return uf.countRoots();
}
int main(){
vector<string> sequences1 = {"a", "b", "ab", "cde"};
cout << numHomologyGroups(sequences1) << endl; // Output: 2
vector<string> sequences2 = {"a", "ab", "abc", "ac"};
cout << numHomologyGroups(sequences2) << endl; // Output: 1
return 0;
}