bluecode-基因序列同源分组问题

问题描述

用不含重复字母的字符串表示一段基因序列。如果一段基因序列可以通过以下任一操作得到另一个基因序列,则认为这两段基因是同源的(或者说有血缘关系):

  1. 增加一个字母
  2. 删除一个字母
  3. 改变一个字母

给定若干个基因序列,求一共有多少种不同的血缘关系(即连通分量的数量)。

输入规范

  • 输入仅包含小写字母
  • 基因序列的总数量不超过 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;
}
相关推荐
BUG收容所所长1 小时前
栈的奇妙世界:从冰棒到算法的华丽转身
前端·javascript·算法
XRZaaa1 小时前
常见排序算法详解与C语言实现
c语言·算法·排序算法
@我漫长的孤独流浪1 小时前
数据结构测试模拟题(4)
数据结构·c++·算法
智驱力人工智能2 小时前
智慧零售管理中的客流统计与属性分析
人工智能·算法·边缘计算·零售·智慧零售·聚众识别·人员计数
WindSearcher3 小时前
大模型微调相关知识
后端·算法
取酒鱼食--【余九】3 小时前
rl_sar实现sim2real的整体思路
人工智能·笔记·算法·rl_sar
Magnum Lehar4 小时前
vulkan游戏引擎test_manager实现
java·算法·游戏引擎
水蓝烟雨5 小时前
[面试精选] 0094. 二叉树的中序遍历
算法·面试精选
超闻逸事5 小时前
【题解】[UTPC2024] C.Card Deck
c++·算法
暴力求解5 小时前
C++类和对象(上)
开发语言·c++·算法