打印所有字符串,O(2 ^ n)算法

时间:2013-09-13 14:09:55

标签: c++ algorithm

假设有n个级别,并且在每个级别中,您可以从两个可能的字符中选择一个,打印所有可能的字符串
如: -
假设我们有3个级别: - level1: - a b
level2: - c d
level3: - e f

可能的字符串是: - 王牌 2. acf
ade adf
5. bce
6. bcf
7. bde
8. bdf

我知道样本空间是2 ^ n所以所需的时间是O(2 ^ n),但我无法弄清楚如何编写它。 有什么可能的方法和我必须阅读哪些主题来解决这些问题?

5 个答案:

答案 0 :(得分:5)

选择两个选项可以轻松实现。把它归为一点。像这样:

char buf[3];
for(unsigned i = 0; i < 10; ++i)
{
    buf[0] = i & 4 ? 'b' : 'a';
    buf[1] = i & 2 ? 'd' : 'c';
    buf[2] = i & 1 ? 'f' : 'e';

    std::string str = std::string(buf, 3);
}

答案 1 :(得分:2)

在我看来,递归是正确答案。

你所拥有的本质上是一个三位二进制数字,其中0和1以外的字符代表数字。

生成所有组合包括简单地计算所有数字到极限,然后使用这些位来选择正确的字符。

这也可以概括。例如,如果您在每个级别有五个级别和六个选项,那么您将查看基础6中的5位数字(然后是每个数字可以表示的字符的2D集合)。

就个人而言,我认为我不会使用long if / then / else(或等效的三元运算符)。如上所述,我使用2D集合,只是索引到该集合:

char const *names [] = { "ab", "cd", "ef" };

for (unsigned i = 0; i < 8; i++) 
    std::cout << names[0][i >> 0 & 1]
              << names[1][i >> 1 & 1]
              << names[2][i >> 2 & 1]
              << "\n";

虽然条件运算符(几乎不可用)可用于这个微不足道的案例,但对于任何较大版本的问题(例如,5位数,基数为6的版本),它们很快变得难以处理。

答案 2 :(得分:1)

您似乎正在寻找的明显(并且无可否认的丑陋)方法使用三个嵌套循环:

char level1[] = "ab";
char level2[] = "cd";
char level3[] = "ef";

int x, y, z;

for (x = 0; x < 2; ++x)
{
    for (y = 0; y < 2; ++y)
    {
        for (z = 0; z < 2; ++z)
        {
            printf("%c%c%c\n", level1[x], level2[y], level3[z]);
        }
    }
}

答案 3 :(得分:0)

具有任意数量级别的平凡算法(也会执行大量复制字符串):

class StringCombinations {
  public:
  // filled somehow
  std::vector<std::pair<char, char> > choices;

  void printStrings(size_t level, std::string prefix) {
    assert(level < choices.size());
    if (level == choices.size() - 1) {
      cout << prefix << choices[i].first();
      cout << prefix << choices[i].second();
    } else {
      printStrings(level +1, prefix + choices[i].first());
      printStrings(level +1, prefix + choices[i].second());
    }
  }
}

这样叫:

StringCombinations sc;
// Set the choices table somehow.
...
sc.printStrings(0, "");

当然,选择表也可以是另一个作为const-reference传递的方法参数,如果你有一个静态方法更方便的话。

-

一个更好的选择(只是针对3个级别提出的n级回答的概括),而没有复制递归调用(尽管不太容易理解):

请注意,如果您不直接打印,则可以使用cout <<重新mystring +=

// all strings have size 2, 0'th char and 1'st char correspond to the choices 
std::vector<std::string> choices;

void printStrings() {
  for (size_t i = 0; i < static_cast<size_t>(pow(2, choices.size())); ++i) {
    for (size_t j = 0; j < choices.size(); ++j) {
      // Checks the bit in i (from the right) that fits the current level (j).
      cout << choices[j][i & (j << x)];
      // 2^#levels different values of i, ensure as many different outcomes
      // (disregarding trivial choices between, e.g., 'a' and 'a'
    }
  }
}

答案 4 :(得分:0)

您可以将int从1迭代到pow(2,n)并查看每个索引的二进制表示。如果该位为0则使用左侧,如果该位为1则使用右侧:

void PrintDigits(char **str, int size, int val)
{
    char *tmp = new char[size + 1];
    assert(tmp);

    tmp[size] = '\0';
    while (size) {
        tmp[size - 1] = str[size - 1][val % 2];
        val = val >> 1;
        size --;
    }

    printf("%s\n", tmp);
}

int main(int argc, char *argv[])
{
    char *str[] = {"ab", "cd", "ef", "gh"};

    int len = sizeof(str) / sizeof(str[0]);

    for (int i = 0; i < (1 << len); i++) {
        PrintDigits(str, len, i);
    }

    return 0;
}

输出:

aceg
aceh
acfg
acfh
adeg
adeh
adfg
adfh
bceg
bceh
bcfg
bcfh
bdeg
bdeh
bdfg
bdfh