2012-04-12 85 views
1

我在互联网上搜索了很多如何做到这一点,但我没有想出一些我完全理解的东西。从字母组获取文字组合

进出口试图通过指定的信量来计算每个组中,例如,以产生从字母阵列中的所有可能的组合:

字母:A, B, C

长度:2

结果: AB, AC, BC

(我知道有:BA,CACB太,但我只需要得到该组的顺序没关系)

例子2:

字母:A, B, C, D

长度:3

结果:ABC, ACD, BCD, CDA, DAB

等..

我打算在C++中实现该算法,但C#,Java或Javascript中的示例是welc ome也是如此。

+0

似乎相当密切相关[这个问题](http://stackoverflow.com/questions/361/产生 - - 的 - 所有可能的 - 排列对的一字符串列表)。 – Geoff 2012-04-12 15:35:57

+0

生成部分组可能更容易,如果您在内部始终按升序生成它们,如:'abc','acd','bcd','acd','abd'...并按abc,abd ,acd - 啊,你有两次!看到! – 2012-04-12 15:37:44

+0

下面是一个Python实现:http://docs.python.org/library/itertools.html#itertools。组合 – 2012-04-12 15:48:17

回答

1

如果你在一个可再现的方式进行订购,你会发现一个算法更容易产生他们:

让我们把它不太容易,拿3分:

e d c b a 
--------- 
    x x x abc 
    x x x abd 
x  x x abe 
    x x x acd 
x x x ace 
x x  x ade 
    x x x bcd 
x x x bce 
x x x bde 
x x x  cde 
+0

谢谢!这非常有帮助! – UnTraDe 2012-05-31 12:31:39

1

似乎很适合递归。取每个元素,并将其添加到其余的组合中,直到满足给定的深度。

static List<String> func(List<String> a, Int32 depth) 
{ 
    List<String> retVal = new List<String>(); 
    if (depth <= 0) 
    { 
     return retVal; 
    } 
    for (int i = 0; i < a.Count; i++) 
    { 
     String element = a[i]; 

     List<String> temp = new List<String>(a); 
     temp.RemoveAt(i); 
     List<String> resultset = func(temp, depth - 1); 
     if (resultset.Count == 0) 
     { 
      retVal.Add(element); 
     } 
     else 
     { 

      foreach (String result in resultset) 
      { 
       retVal.Add(element + result); 
      } 
     } 
    } 
    return retVal; 
} 
0

这应该工作,如果你稍微调整它:

void r_nCr(const unsigned int &startNum, const unsigned int &bitVal, const unsigned int &testNum) // Should be called with arguments (2^r)-1, 2^(r-1), 2^(n-1) 
{ 
    unsigned int n = (startNum - bitVal) << 1; 
    n += bitVal ? 1 : 0; 

    for (unsigned int i = log2(testNum) + 1; i > 0; i--) // Prints combination as a series of 1s and 0s 
     cout << (n >> (i - 1) & 1); 
    cout << endl; 

    if (!(n & testNum) && n != startNum) 
     r_nCr(n, bitVal, testNum); 

    if (bitVal && bitVal < testNum) 
     r_nCr(startNum, bitVal >> 1, testNum); 
} 

说明here

1

这被称为排列,有很多解决方案。 这是一个非递归的,我写的速度非常快。 (如果你在Windows上,你可能需要查找_BitScanReverse而不是__builtin_ctz)。

#include <iostream> 
#include <cstdlib> 
using namespace std; 

void perm(unsigned &v) { //v must be initialised with t = (2 << N) - 1; 
    unsigned t = v | (v - 1); 
    v = (t + 1) | (((~t & -~t) - 1) >> (__builtin_ctz(v) + 1)); 
} 

int main (int argc, char *argv[]) { 
    unsigned n = argc > 1 ? atoi(argv[1]) : 3; //bins: 0..31 
    unsigned k = argc > 2 ? atoi(argv[2]) : 2; //things: 0 .. bins. 
    unsigned m = (1 << n) - 1; //bitmask is size of n (bins). 
    unsigned v = (1 << k) - 1; //start value - initial allocation. 
    do { 
     cout << bitset<31>(v & m) << endl; 
     perm(v); 
    } while (v < m); 
    return 0; 
} 

在你的问题中,你建议 - 字母:A,B,C长度:2为例。 所以,这个代码将产生(通过3 2作为参数)(我曾评论)

ABC 
011 //BC 
101 //AC 
110 //AB