簡體   English   中英

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

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

假設有n個級別,並且在每個級別中,您可以從兩個可能的字符中選擇一個,打印所有可能的字符串
例如:-
假設我們有3個級別:
1級:-ab
2級:-CD
等級3:-ef

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

我知道樣本空間為2 ^ n,因此所需的時間為O(2 ^ n),但我不知道如何進行編碼。 有什么可能的解決方案?要解決這些問題,我必須閱讀哪些主題?

選擇兩個選項即可輕松實現。 將其壓縮成位。 像這樣:

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

我認為,遞歸不是解決此問題的正確方法。

您實際上擁有的是一個三位數的二進制數字,用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為底的版本),它們很快就會變得笨拙。

您似乎正在尋找的顯而易見的(而且很丑陋)的方法使用了三個嵌套循環:

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

具有任意數量級別的簡單算法(也執行很多復制字符串):

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

當然,choices表也可以是作為const引用傳遞的另一個方法參數,如果這樣做對於您來說有一個靜態方法更方便。

-

一個更好的選擇(只需將3個級別的答案概括為n個級別),而無需為遞歸調用進行所有復制(不過,較難理解):

請注意,如果您不直接打印,當然可以用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'
    }
  }
}

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM