【问题标题】:Create all possible permutations of given variable set创建给定变量集的所有可能排列
【发布时间】:2015-02-06 13:30:43
【问题描述】:

我遇到了与反向翻译有关的问题。
问题本身可以表述为:给定 20 个唯一字母(对应 20 个氨基酸)的字符集,每个字母由 3 个字符组成的代码生成[A、T、G、C 中的任意 3 个]。生成编码给定氨基酸序列/字符串的所有可能的核苷酸序列。
20 种氨基酸有 64 种可能的核苷酸 [ATGC] 组合。 例如:赖氨酸,用字母K表示,由两个三联体(=密码子)AAA和GAA编码。

正向翻译很好,因为我可以将三联体映射到氨基酸密码,但问题在于反向翻译,其中三联体的各种组合是可能的,因为大多数氨基酸可以由多个密码子编码。

这是我的程序的基本框架:

 //Map all Amino Acids with their corresponding codons.
std::map<std::string, string, std::less<std::string> >  somevar;
somevar["K"]="AAA|GAA";......so on.

//Take input in string of Amino Acid single letter codes.
//Split each Amino acid into corresponding codons using stringstream
while(std::getline(ss, token, '|')){}

//Store the values in vector.

第一个问题:由于我不知道输入字符串的大小,我需要动态向量数组或向量向量。 (简单地说,如果发生类似 KK 的情况,将有两个数组类型变量存储 KK 的所有三元组。)有没有办法消除这种冗余(直接查看某个表)?

//Pass the arrays to a function which will return all possible permutations.

第二个问题:在解决了第一个问题后,我想用给定的氨基酸串创建所有可能的核苷酸序列组合。(即,从每个新创建的数组(集合)派生的所有可能组合)。
KK 会导致:AAAGAA,AAAAAA,GAAAAA,GAAGAA。

唯一的限制是复杂度应该是〜O(n ^ 2),我想知道我是否可以递归地做到这一点,或者C ++中是否有一些内置函数/库可以帮助我生成所有给定(变量)数据集的可能排列。

编辑:另一个例子 假设随机字母 A 有 3 个密码子,字母 Y 有 5 个密码子,那么组合的总数将为 3*5。

如果 M=AAT,ATA 且 N=GTT,AGT,TGT,则结果将为 1)AATGTT,2)ATAGTT,3)ATAGT,4)AATTGT,5)ATAAGT,6)ATATGT

【问题讨论】:

  • std::next_permutation 可能有用。
  • 在申请std::next_permutation之前记得std::sort,这样你就不会错过之前的排列。
  • @NickyC,我正在研究 std::next_permutation,我不确定是否可以在多维数组的上下文中实现它。
  • @Siddharth 只是展平数组表示?
  • @larnvst,无论如何我都需要扩展数组,因为在 n 之前存在多种组合。

标签: c++ arrays algorithm set bioinformatics


【解决方案1】:

以下可能会有所帮助:

std::vector<std::string> translate(const std::vector<std::string>& v,
                                const std::map<std::string, std::vector<std::string>>& mapping)
{
    if (v.empty()) {
        return {};
    }
    std::vector<std::string> res = {""};

    for (const auto& s : v) {
        std::vector<std::string> tmp;

        for (const auto& seq : mapping.at(s)) {
            for (const auto& old: res) {
                tmp.push_back(old + seq);
            }
        }
        res = std::move(tmp);
    }
    return res;
}

与:

  • v要翻译的序列
  • mapping"K"{"AAA", "GAA"}之间的映射

Live example

【讨论】:

  • 代码本身可以完美运行,尽管我担心它可能无法满足 O(n^2) 的标准。我想我可能可以稍微修改一下,但是将其转换为递归函数是不可能的。
  • @Siddharth:将函数转换为递归不会改变复杂性。您必须遍历 Cartesian product。您可以使用其他算法来迭代可能性而不生成整个向量。
【解决方案2】:

您真的想要获得所有排列(所有可能的密码子排序),还是所有可能的字母到密码子的翻译(更像是谐音替换)?

如果是后者,对于您的问题 2,如果所有字母都有 2 个可能的密码子(远大于 O(n^2)),则输出字符串的数量将为 O(2^n)。

您仍然可以使用递归函数相对简单地实现它(或者不使用,就像 @Jarod42 所做的那样)。

对于您的问题 1,我认为您的过程的输入实际上是一种存储输出的紧凑方式... 对于一个输入字符串,您的返回类型可以是 std::vector&lt;std::string&gt;,所以您可以为所有输出字符串选择 std::vector&lt;std::vector&lt;std::string&gt; &gt;

【讨论】:

  • 我用一个例子编辑了我的问题。它可以或多或少地表述为该字母的所有可能的密码子组合,以生成所有可能的序列。很像 CodonArrayforA[1]*CodonArrayforB[2] 之间的所有组合
  • 所以我认为@Jarod42 的代码适合你。
  • 它正在工作,但我仍在设计一个上限为 n^2 的实现。
  • 我担心这是不可能的,因为如果字母 ini 可能的翻译,你的输出大小是 n1*n2*...*nk
  • 我同意,虽然我确实想到了一些完全不同的东西,也就是说,减少常见密码子以减少简并(如果 A 由 GAT 和 GAA 编码,则简化形式对应于 GA[X]) .这可能会稍微降低计算成本,但仍无助于降低时间复杂度。最后,处理文本总是很麻烦。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-12-07
  • 1970-01-01
  • 1970-01-01
  • 2014-03-11
  • 1970-01-01
  • 2011-07-27
相关资源
最近更新 更多