简体   繁体   English

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

[英]Print all strings, O(2^n) algorithm

Suppose there are n levels and in each levels you can choose one out of two possible characters, Print all possible strings 假设有n个级别,并且在每个级别中,您可以从两个可能的字符中选择一个,打印所有可能的字符串
eg:- 例如:-
Suppose We have 3 levels:- 假设我们有3个级别:
level1 :- ab 1级:-ab
level2 :- cd 2级:-CD
level3 :- ef 等级3:-ef

possible strings are:- 1. ace 可能的字符串是:1. ace
2. acf 2. acf
3. ade 3. ade
4. adf 4. adf
5. bce 5.公元前
6. bcf 6. bcf
7. bde 7. bde
8. bdf 8. bdf

I know that the sample space is 2^n so the time required is O(2^n), but I can't figure out how can I go about coding it. 我知道样本空间为2 ^ n,因此所需的时间为O(2 ^ n),但我不知道如何进行编码。 What could be possible approches and what topics do I have to read to solve such problems? 有什么可能的解决方案?要解决这些问题,我必须阅读哪些主题?

Having a pow-of-two number of choices makes this easy. 选择两个选项即可轻松实现。 Condence it into bits. 将其压缩成位。 Something like this: 像这样:

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);
}

In my opinion, recursion is not the right answer for this. 我认为,递归不是解决此问题的正确方法。

What you have is essentially a three-digit binary number, with characters other than 0 and 1 to represent the digits. 您实际上拥有的是一个三位数的二进制数字,用0和1以外的其他字符表示这些数字。

Generating all the combinations consists of simply counting through all the numbers up to the limit, then using the bits to choose the correct characters. 生成所有组合的过程包括简单地对所有数字进行计数直至达到极限,然后使用这些位选择正确的字符。

This can also be generalized. 这也可以概括。 For example, if you had five levels and six choices at each level, you'd be looking at a 5 digit number in base 6 (and then a 2D collection of the characters each digit can represent). 例如,如果您有五个级别,每个级别有六个选择,那么您会看到以6为底的5位数字(然后是每个数字可以表示的2D字符集合)。

Personally, I don't think I'd use a long if/then/else (or, equivalently, ternary operators) for this. 就我个人而言,我认为我不会为此使用较长的if / then / else(或等效的三元运算符)。 As suggested above, I'd use a 2D collection, and just index into that collection: 如上面的建议,我将使用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";

While conditional operators are (barely) usable for a case this trivial, for any larger version of the problem (eg, the 5-digit, base-6 version), they quickly become unwieldy. 尽管条件运算符在这种琐碎的情况下(几乎)可用,但对于任何较大版本的问题(例如5位数,以6为底的版本),它们很快就会变得笨拙。

The obvious (and admittedly ugly) method you seem to be looking for uses three nested loops: 您似乎正在寻找的显而易见的(而且很丑陋)的方法使用了三个嵌套循环:

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]);
        }
    }
}

The trivial algorithm with an arbitrary number of levels (also does a lot of copying strings): 具有任意数量级别的简单算法(也执行很多复制字符串):

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());
    }
  }
}

called like this: 这样称呼:

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

the choices table could, of course, also be another method parameter that is passed as const-reference, if it is more convenient for you to have a static method for this. 当然,choices表也可以是作为const引用传递的另一个方法参数,如果这样做对于您来说有一个静态方法更方便。

-- -

A better alternative (just the generalization to n levels of what otehr answers proposed for 3 levels) without all that copying for the recursive calls (less understandable, though): 一个更好的选择(只需将3个级别的答案概括为n个级别),而无需为递归调用进行所有复制(不过,较难理解):

Note that you can, of course, repalce cout << with mystring += if you do not print directly. 请注意,如果您不直接打印,当然可以用mystring +=替换cout <<

// 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'
    }
  }
}

You can iterate an int from 1 to pow(2, n) and look at the binary representation of each index. 您可以将int从1迭代到pow(2,n),然后查看每个索引的二进制表示形式。 Use the left if the bit is 0, the right if the bit is 1: 如果该位为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;
}

Output: 输出:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM