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;
}
相关推荐
GreenTea19 分钟前
OpenAI Agents API 上手实测:一次调用把整个 agent loop 甩给 OpenAI
前端·后端·算法
深圳满意度咨询1 小时前
医院满意度数字化测评系统:从数据采集到智能决策的技术实践
算法
xiangyun612 小时前
【408数据结构 08】队列:循环队列判空判满,408年年考,一次讲清
c语言·开发语言·数据结构·c++·算法
xiangyun612 小时前
【408数据结构 06】双链表、循环链表、静态链表
c语言·开发语言·数据结构·c++·算法
302wanger4 小时前
推荐下我的两个AI信息源
算法
索尔~古德曼4 小时前
CF——错题的集合
算法
SL_staff4 小时前
JVS-Logic:从页面配置工具到企业级业务逻辑中枢的技术演进
java·算法·全栈
陌シ未央ゞ4 小时前
基于BM25算法和RRF实现的混合索引(java版)
人工智能·spring boot·后端·算法
renhongxia14 小时前
数字孪生不止在工厂:能源、医疗与农业
人工智能·深度学习·算法·机器学习·数字孪生
Navigator_Z4 小时前
LeetCode //C - 1250. Check If It Is a Good Array
c语言·算法·leetcode