【问题标题】:Every permutation of the alphabet up to 29 characters?字母表的每个排列最多 29 个字符?
【发布时间】:2011-01-05 23:01:38
【问题描述】:

我正在尝试编写一个程序,该程序将生成一个文本文件,其中包含从一个字符到二十九个字符的所有可能的字母排列。我选择了 29 作为大家都知道的最长英语单词 antidisestablishmentarianism,它有 28 个字符。有更长的,但它们主要是非常技术性和晦涩的。

我意识到这会产生大量的字符串。但是我不知道从哪里开始,甚至不知道如何计算这会产生多少组合。

请回答 PHP、Processing、C++ 或 Java 中的解决方案(我只熟悉这些,首选 PHP,但可能不是我想像的最好的)。

甚至只是伪代码/想法都会受到赞赏。

另外,在有人说之前,这不是用于暴力破解或类似的东西。我是一名艺术家,尽管对我的概念有些陌生和模糊。

【问题讨论】:

  • 我希望你明白这个文本文件有多大。最好多买几块硬盘。
  • 我们整个星球的组合存储空间无法存储该列表。
  • 哦。我猜是未来的一个。
  • 我们是在谈论单个单词的排列还是字母表中的字母的组合?从这个问题我不清楚。
  • 既然是艺术项目,结果可能不需要存储。也许它可以闪烁指向大麦哲伦星云或其他东西的 LED?

标签: java php c++ processing permutation


【解决方案1】:

“排列”这个词通常意味着每个字母只出现一次,因此不可能生成任何超过 26 个字母的排列。反正生成的字符串数量太多了,可以用随机字符串代替(下面是C代码):

char s[30];
int p;
for (;;) // repeat forever: you cannot use a realistic iteration limit anyway
{
    for (p = 0; p < 29; ++p)
        s[p] = 'a' + rand() % 26;
    s[29] = '\0';
    puts(s);
}

【讨论】:

  • 不是很系统,是吗:)
  • 这是不正确的,你给出了组合的定义,排列是使用组合的构造,例如:字母a,b和c的组合可以构造排列abc或aabbcc或abbbbc等...
  • 确实,您给出的是组合的定义,而不是排列。组合起来,abc 和 acb 是一样的。但在排列中,abc 和 acb 是两种不同的排列方式。
【解决方案2】:
void out_perms(std::string word) {
    std::vector<int> indexes(word.size());
    for (size_t i = 0; i < indexes.size(); ++i)
        indexes[i] = i;
    do {
        for (size_t i = 0; i < indexes.size(); ++i)
            std::cout << word[indexes[i]];
        std::cout << std::endl;
    } while (std::next_permutation(indexes.begin(), indexes.end()));
}

int main(int, char**) {
    out_perms("asdfg");
}

例如输出见http://codepad.org/6lQTPQrG

【讨论】:

  • 我将“字母表的所有可能排列”解释为“字母表中所有可能的字母组合”,即从“a”到“aaaaa”再到“zzzzz”。
【解决方案3】:

显然,外部的 for 循环用于计算单词中的字符数。然后,您只需创建具有该长度的字符串。对于长度 5,您从“AAAAA”开始,然后是“AAAAB”、“AAAAC”。

点击“Z”后,您返回并将角色向上移动到左侧,即“AAAAZ”变为“AAABA”,“AAAZZ”变为“AABAA”。一旦你点击“ZZZZZ”,你就完成了内循环,然后外循环将以“AAAAAA”开始。

【讨论】:

  • 我相信这个概念更容易理解为以 26 为基数。第一个“数字”从 A 到 Z,然后是 AA、AB、...、AZ,然后是 BA,依此类推。
  • 是的,和从 1 数到 999999 一样,只是你使用字母作为数字。
【解决方案4】:

这是一个简单的未经测试的 C++ 程序,它通过以 Base 26 计数来创建单词:

#include <string>
#include <iostream>

int main(void)
{
    //----------------------------------------------------------
    //  Print permuations of strings of letters up to length 5.
    //  Use base 26 arithmetic.
    //----------------------------------------------------------
    const unsigned int MAX_ITERATIONS = 26 * 26 * 26 * 26 * 26;

    std::string word = "A";
    for (unsigned int i = 0; i < MAX_ITERATIONS; ++i)
    {
        //------------------------------------------------------
        //  Print the word
        //------------------------------------------------------
        std::cout << word << std::endl;

        //------------------------------------------------------
        //  Increment the word, using base 26 arithmetic.
        //  A, B, C, ..., Z.
        //  AA, BA, CA, ..., ZA, AB, BB, CB, DB, ..., ZZ.
        //  AAA, BAA, CAA, ..., ZAA, ABA, BBA, CBA, DBA, ..., ZZZ.
        //------------------------------------------------------
        bool            carry_generated = false;
        unsigned int    digit = 0;
        do
        {
            carry_generated = false;
            if (word[digit] < 'Z')
            {
                ++word[digit];
                break;
            }
            word[digit++] = 'A';
            if (word.length() == digit)
            {
                word += "A";
                break;
            }
            carry_generated = true;
        } while (carry_generated && (digit < 5));
    }

    return 0;
}

可以通过在打印前检查单词列表(也称为字典)来减少打印的单词数。如果单词在单词列表中,则打印它。

字长为 29 的最大问题是表示数量。数量超出了标准 C++ 无符号整数的范围。需要使用 Big Int 库。 下一个问题是处理每个组合所需的时间。 每次迭代将数量乘以 1 微秒(一种更坏的情况)并减少到天、小时、分钟和秒。也许可能需要几年时间。

【讨论】:

  • 谢谢托马斯,这是一个很好的答案。是的,我没想到它会超过整数长度。
  • 我的粗略估计是 8.9E+29 年,假设每次迭代 1 微秒,总共 26^30(26 的 30 次方)迭代(它应该少一,但这微不足道数量如此之大)。我可能是错的......
【解决方案5】:

使用 PHP 的 Perl 风格的字符递增。

set_time_limit(0);

$perm = 'A';
$endTest = str_repeat('Z',28).'A';
while ($perm != $endTest) {
    echo $perm++,"\n";
}

从命令行运行脚本,这样您就不会遇到网络服务器超时;然后坐下来等待几年完成

【讨论】:

  • 很好的解决方案,谢谢。我会在开水壶的时候打开它。
【解决方案6】:
function p($length, $partial)
{
      if ($length == 0) return $partial;
      $ans = array();
      foreach (range('a', 'z') as $i)
      {
          $ans[] = p($length -1, $partial . $i);
      }
      return $ans;  
}

$top = 3;
//$f = fopen('out.txt');
for ($l = 1; $l < $top+1; $l++)
{
     print_r(p($l), '');
     //fwrite($p($l), '');
}

如果您想将 $top 设置为 29 并尝试一下,请继续。我不会。

编辑 - print_r(p($l), ''); ---> print_r(p($l, ''));

PHP 对错误的容忍度一直给我留下深刻印象。我的p 缺少“必需”参数?没问题,它只是以某种方式为空字符串(或零,或假,视情况而定)。 print_r 的第二个 '' 参数?没有区别,无论如何都会被视为默认的false

编辑

我不知道我到底在做什么。 p 的不同返回类型很奇怪,会返回一个结构怪异的复合数组。

无论如何,这是一个更好的解决方案

$lengthDesired = 29;
for($i='a'; $i != str_pad('',$lengthDesired+1,'a'); $i++)
    echo $i .', ';

【讨论】:

    【解决方案7】:

    这是一个用 java http://www.merriampark.com/perm.htm 编写的排列生成器。

    正如他所说的

      //-----------------------------------------------------------
      // Constructor. WARNING: Don't make n too large.
      // Recall that the number of permutations is n!
      // which can be very large, even when n is as small as 20 --
      // 20! = 2,432,902,008,176,640,000 and
      // 21! is too big to fit into a Java long, which is
      // why we use BigInteger instead.
      //----------------------------------------------------------
    

    由于您的n 是 29,您将等待很长时间。它太大了,因为 EboMike 试图在他的 cmets 中告诉你。

    【讨论】:

    • 是的,我知道它会很大。完全没有意识到有多大。我确信以某种形式显示此信息是可能的。这可能是更大的挑战,而不是生成组合。
    【解决方案8】:

    就在我的脑海中(PHP)。

    $index = 0;
    
    while(1) {
       $output_string = '';
       $base_26 = (string)base_convert($index, 10, 26);
       if (strlen($base_26) > 29) break;
       for ($i = 0; $i < strlen($base_26); $i++) {
          $output_string .= chr(65 + base_convert($base_26[$i], 26, 10));
       }
       $index++;
       echo $output_string;
    }
    

    【讨论】:

    • 脚本很可能最终会中断。
    【解决方案9】:

    这就是我要做的:

    #include <iostream>
    
    void printWords(std::string& word, int index, int last)
    {
        std::cout << word << "\n";
        if (index != last)
        {
            for(char loop = 'a'; loop <= 'z'; ++loop)
            {
                word[index] = loop;
                printWords(word, index+1, last);
            }
            word[index] = ' ';
        }
    }
    
    int main()
    {
        std::string word("                             "); // 29 space
    
        printWords(word,0,word.length());
    }
    

    【讨论】:

      【解决方案10】:

      应该可以解决问题的 Java 解决方案:

      public void characterPermutations(int length, LinkedList<String> permutations) {
          if(length > 1) {
              characterPermutations(length - 1, permutations);
      
              ListIterator<String> iterator = permutations.listIterator();
              while(iterator.hasNext()) {
                  String permutation = iterator.next();
                  for(char c = 'a'; c <= 'z'; c++) {
                      iterator.add(c + permutation);
                  }
              }
      
          } else {
              for(char c = 'a'; c <= 'z'; c++) {
                  permutations.add(c + "");
              }
          }
      }
      

      【讨论】:

        【解决方案11】:
        public class hii {  
        
        public static void main(String[] args){
        
            String[] database = {"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"};
        
            for(int i=1; i<=database.length; i++){
                String[] result = getAllLists(database, i);
                for(int j=0; j<result.length; j++){
                    System.out.println(result[j]);
                }
            }
        
        
        
        }
        
        
            public static String[] getAllLists(String[] elements, int lengthOfList)
            {
                //initialize our returned list with the number of elements calculated above
                String[] allLists = new String[(int)Math.pow(elements.length, lengthOfList)];
        
                //lists of length 1 are just the original elements
                if(lengthOfList == 1) return elements; 
                else {
                    //the recursion--get all lists of length 3, length 2, all the way up to 1
                    String[] allSublists = getAllLists(elements, lengthOfList - 1);
        
                    //append the sublists to each element
                    int arrayIndex = 0;
        
                    for(int i = 0; i < elements.length; i++){
                        for(int j = 0; j < allSublists.length; j++){
                            //add the newly appended combination to the list
                            allLists[arrayIndex] = elements[i] + allSublists[j];
                            arrayIndex++;
                        }
                    }
                    return allLists;
                }
            }
        
        
        
        
        
        
        }
        

        【讨论】:

          【解决方案12】:

          我能想到的最简单的方法是在伪代码中获得从 1 个字符到 29 个字符的每个排列:

          loop from i = 1 to 26^29 or 27^29 if you want to include spaces
          {
             convert i to base 26 or 27;
             translate each number to the corresponding letter;
          }
          

          【讨论】:

            【解决方案13】:

            即使您可以将其存储在磁盘上,就像 thirydot 指出的那样,您也没有时间这样做了。

            在我的计算机上仅生成(而不是存储)所有 6 个字母的可能性需要 24 秒:

            $ time perl letters.pl
            
            real    0m24.837s
            user    0m24.765s
            sys     0m0.030s
            

            每个单词需要 7.7X10^-8s,这意味着需要 8.4x10^33s 或 2.6x10^26 年。

            您需要更多地考虑您的算法。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2017-08-10
              • 2013-05-14
              • 2023-03-13
              • 2022-11-12
              • 2013-05-14
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多