【问题标题】:Print all strings, O(2^n) algorithm打印所有字符串,O(2^n) 算法
【发布时间】:2013-09-13 14:09:54
【问题描述】:

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

可能的字符串是:- 1.王牌
2.acf
3.阿德
4. adf
5. 公元前
6. bcf
7. bde
8. bdf

我知道样本空间是 2^n,所以所需的时间是 O(2^n),但我不知道如何进行编码。 有哪些可能的方法以及我必须阅读哪些主题才能解决这些问题?

【问题讨论】:

标签: c++ algorithm


【解决方案1】:

拥有两个选项的 pow 使这很容易。把它压缩成小块。像这样的:

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

【讨论】:

  • 请注意2*2*2 != 10
  • 谢谢它工作正常,只有迭代次数应该是 2^levels,
  • 谢谢,我很容易将它概括为 n 个级别!但是请您详细说明它是如何工作的!
【解决方案2】:

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

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

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

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

就我个人而言,我认为我不会为此使用长的 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 为底的版本),它们很快就会变得笨拙。

【讨论】:

  • +1 表示 LUT。我考虑过,但最终还是使用了分支,因为我认为它们更好地传达了总体思路。如果有两种以上的可能性,肯定会推荐使用 LUT。
【解决方案3】:

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

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
  • @Hidetoshi:是的,这是真的。其他答案显示了如何模拟多个循环(例如使用递归),或者使用带有一些巧妙数学的单个循环。
【解决方案4】:

具有任意数量级别的简单算法(也做了很多复制字符串):

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, "");

当然,选择表也可以是作为常量引用传递的另一个方法参数,如果您为此使用静态方法更方便的话。

--

一个更好的替代方案(只是对 3 个级别的 otehr 答案提出的 n 个级别的概括),而不需要对递归调用进行所有复制(虽然不太容易理解):

请注意,如果您不直接打印,当然可以将 cout &lt;&lt; 替换为 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'
    }
  }
}

【讨论】:

    【解决方案5】:

    您可以将 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
    

    【讨论】:

      猜你喜欢
      • 2020-07-19
      • 1970-01-01
      • 1970-01-01
      • 2011-12-22
      • 1970-01-01
      • 1970-01-01
      • 2019-12-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多