【问题标题】:C - Generating all possibilities of X character wordsC - 生成 X 字符单词的所有可能性
【发布时间】:2012-03-03 06:24:04
【问题描述】:

编辑:我的意思是排列,而不是组合。谢谢。

我意识到这是一个相当开放的问题,我并不是在寻找代码,而是真正从哪里开始寻找一些提示。我想做的是一个程序,它可以生成给定长度的每个字符组合,即用户输入 4,程序将生成长度为 4 的每个可能的 ASCII 字符组合。

不太确定我会从哪里开始,也许是使用哈希表?当然需要循环,但我不确定如何设计它们以产生组合。到目前为止,它一直是一个循环,直到发生了 1000 件事情。

非常感谢任何建议!

干杯,

T。

【问题讨论】:

  • 我看不出有什么理由需要哈希表,但循环可能是个好主意,是的。试着问一个更具体的问题,包括你尝试过什么,什么没用。
  • 只是我不知道从哪里开始! :)
  • 听起来像是递归的例子!
  • 你是指每个组合还是每个排列。例如,abba 是否不同?
  • 有一个read

标签: c arrays loops hash


【解决方案1】:

对于排列,您可以使用这样的递归解决方案(可能可以优化和改进):

unordered_set<string> permute_string(int n) {    
    static const char chars[] = {
        'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
        'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
    };

    unordered_set<string> s;

    if (n == 0) {
        s.insert("");

        return s;
    }

    unordered_set<string> perms = permute_string(n - 1);

    for (auto c = std::begin(chars); c < std::end(chars); ++c)
        for (auto i = perms.begin(); i != perms.end(); ++i)
            for (int pos = 0; pos < n; ++pos)
                s.insert(string(*i).insert(pos, 1, *c));

    return s;
}

注意这个函数的输出(不管你如何实现)是26n,当n(此函数的输入)为 4。

【讨论】:

  • 我认为您的解决方案不允许重复字符,例如“aaaa”。我知道他说的是排列,但我不确定他是不是这个意思。
  • @KarlBielefeldt 是的,它确实如此(如果你这样做,你可以证明它cout &lt;&lt; *permute_string(4).rbegin() 你得到zzzz
  • 那么你计算计数的公式是错误的。如果允许重复,则为 26^n
  • @KarlBielefeldt 啊,是的,你是对的,我记错了排列公式的作用,我现在更新我的答案
  • 请问,我对 's' 变量和 'unordered_set' 实际上指的是什么感到困惑?这是一个 C++ 代码:) ?
【解决方案2】:

你的问题太笼统了。无论如何,您可以使用trie 数据结构来获得您想要的。但是,如果您要在 c 中执行此操作,则仍然需要大量工作。我建议使用一种不需要重新创建轮子的语言。

【讨论】:

  • 你会使用 trie 来生成排列或组合,什么?
  • 据我了解,OP 想要特定大小的所有字符组合。
  • 好吧,大概你会使用stackoverflow.com/questions/127704/…的组合......不是一个尝试。
【解决方案3】:

是的,这几乎需要递归解决方案。生成所有长度为 N 的单词,基本算法是

pick the next letter from the alphabet
  generate all N-l-length words starting with that letter    

如果您只需在生成这些字符串时将这些字符串打印到文件或其他文件中,那么您就不需要任何复杂的数据结构。您只需要一个缓冲区来保存生成的单词。

重要问题:您确定要所有 ASCII 字符(包括标点符号、控制字符等)的所有可能组合吗?还是所有可能的字母数字字符串组合?还是严格的字母字符串?

你可能想在你的代码中指定你的字母,比如

char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

并且只是索引而不是假设特定的字符表示:

char *p;
for (p = alphabet; *p != 0; p++)
  // generate all words starting with *p

【讨论】:

    【解决方案4】:

    这是我刚刚从 python 方法 itertools.permutations 的文档转换为 C++ 的完整且有效的解决方案。 http://docs.python.org/library/itertools.html#itertools.permutations 。在最初的 python 形式中,它是一个生成器(只是想想迭代器),但我现在没有理会它,尽管它会很有意义。

    permutations 方法是一个模板,因此它适用于您可以存储在向量中的任何对象,而不仅仅是字符。使用此代码:

    vector<char> alphab={'a','b','c','d'};
    auto perms=permutations(alphab,3);'
    

    结果是一个'vector'的向量,代表abcd的所有非重复3-组合:

    abc abd acb acd adb adc bac bad bca bcd bda bdc
    cab cad cba cbd cda cdb dab dac dba dbc dca dcb 
    

    这是代码 (C++11):

    #include <vector>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    size_t nperms(size_t n,size_t k){
       if(k<=0) return 1; // one empty set
       if(k>n) return 0;  // no possible ways
       size_t out=1;
       for (size_t i=n-k+1;i<=n;i++) out*=i;
       return out;
    }
    
    template<class T>
    vector<T > permutations(T & iterable, size_t r=-1){    
       vector<T> out;
       T & pool = iterable;
       size_t n = pool.size();
       r = r>=0 ? r : n;
       if (r > n)
          return out;
       vector<size_t> indices;
       for (size_t i=0;i<n;++i) indices.push_back(i);
       vector<size_t> cycles;
       for (size_t i=n;i>(n-r);--i) cycles.push_back(i);
    
       vector<typename T::value_type> line; //e.g. vector of char
       line.reserve(r);
    
       for (size_t i=0;i<r;++i)
          line.push_back(pool[i]);
       out.reserve(nperms(n,r));    
       // first permutation:
       out.push_back(line);   
       while (1){
         bool done=1;
         for (size_t irev=0;irev<r;++irev){
           size_t i=r-1-irev;
           cycles[i] -= 1;
           if(cycles[i] == 0){
             // cycle upper part one step
             rotate(begin(indices)+i,begin(indices)+i+1,end(indices));
             cycles[i] = n-i;
           }else{
             int j = cycles[i];
             swap(indices[n-j],indices[i]);         
             for (size_t k=0;k<r;++k)
               line[k]=pool[indices[k]];
             out.push_back(line);
             done=0;
             break ;
           }
         }
         if(done) break;
       }
       return out;
    }    
    int main(){
    
       vector<char> alphab={'a','b','c','d'};
       auto perms=permutations(alphab,3);
    
       // print:
       cout <<"perms of size " <<perms.size()<<endl;
       for (auto &i : perms){
          for (auto &j : i){
         cout << j<<"";
          }
          cout <<" ";
       }
       cout <<endl;
       return 0;
    }
    

    作为说明:

    不检查字母表是否唯一,而是通过索引完成排列和选择,因此如果您想允许多个对象中的一个,只需将更多的对象添加到字母表中即可。内容也不必具有可比性。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-23
      • 2021-12-14
      • 2021-09-16
      • 2022-08-24
      • 1970-01-01
      相关资源
      最近更新 更多