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;
}
相关推荐
linx2955 分钟前
单元九 · 零基础路线图-第 7–9 周·类与 RAII
c语言·开发语言·数据结构·c++·嵌入式硬件·算法
布莱克6057 分钟前
C++ 七大排序算法详解:选择、冒泡、插入、计数、堆、快速与归并排序
数据结构·c++·算法·排序算法
shehuiyuelaiyuehao1 小时前
算法44,模拟算法,数青蛙
算法·哈希算法·散列表
hanlin031 小时前
刷题笔记:力扣第287题-寻找重复数
笔记·算法·leetcode
kevin_kang1 小时前
第02章 对话时间线与延迟分析
算法
科学实验家1 小时前
最小生成树:Prim,kruskal
数据结构·c++·算法
学习智者1 小时前
《玄》IDE v3.6.3重磅发布:全功能修复与性能飞跃
开发语言·c++·ide·算法·中文语言 玄
Jasmine_llq1 小时前
《P10263 [GESP202403 八级] 公倍数问题》
算法·数论·快速 io 优化·埃氏筛(倍数枚举)·线性遍历求和
橘子汽水1681 小时前
Leetcode 322 279 零钱兑换,完全平方数
算法·leetcode
kevin_kang2 小时前
第01章 VoiceAgent 的总体架构与完整流程
算法