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;
}
相关推荐
CUMT_DJ39 分钟前
matlab计算算法的运行时间
开发语言·算法·matlab
KyollBM4 小时前
每日羊题 (质数筛 + 数学 | 构造 + 位运算)
开发语言·c++·算法
Univin6 小时前
C++(10.5)
开发语言·c++·算法
Asmalin6 小时前
【代码随想录day 35】 力扣 01背包问题 一维
算法·leetcode·职场和发展
剪一朵云爱着6 小时前
力扣2779. 数组的最大美丽值
算法·leetcode·排序算法
qq_428639616 小时前
虚幻基础:组件间的联动方式
c++·算法·虚幻
深瞳智检7 小时前
YOLO算法原理详解系列 第002期-YOLOv2 算法原理详解
人工智能·算法·yolo·目标检测·计算机视觉·目标跟踪
怎么没有名字注册了啊7 小时前
C++后台进程
java·c++·算法
Rubisco..8 小时前
codeforces 2.0
算法
未知陨落8 小时前
LeetCode:98.颜色分类
算法·leetcode