生成字符串的随机固定长度排列

时间:2008-12-14 19:07:18

标签: algorithm random

让我们说我的字母包含X个字母,我的语言只支持Y个字母(Y< X ofcourse)。我需要以随机顺序生成所有可能的单词。

E.g。 字母表= A,B,C,d,E,F,G Y = 3

所以这些话会是: AAA AAB AAC ABA .. BBB CCC .. (以上应按随机顺序生成)

这样做的简单方法是生成单词然后随机化列表。我不想这样做。我想以随机顺序生成单词。

rondom(n)= letter [x] .random(n-1)将不起作用,因为那时你将有一个以letter [x]开头的单词列表..这将使列表不那么随机。< / p>

任何代码/伪代码都赞赏。

3 个答案:

答案 0 :(得分:1)

正如其他答案暗示的那样,有两种主要方法:1)跟踪您已经生成的内容(此类别中提议的解决方案可能永远不会终止),或2)跟踪尚未生成的排列(意味着必须预先生成排列,这在要求中是特别不允许的)。这是另一种保证终止并且不需要预生成的解决方案,但可能无法满足您的随机化要求(此时这些要求很模糊)。

概述:生成一棵树以跟踪生成的内容或剩余内容。通过遍历树中的随机链接来“选择”新的排列,在生成该排列之后在树叶处修剪树以防止再次生成它。

如果没有白板来表示这一点,我希望这个描述足以描述我的意思:创建一个“节点”,其中包含字母表中每个字母的其他节点的链接。这可以使用字母到字母的通用映射来实现,或者如果你的字母是固定的,你可以创建特定的引用。该节点表示字母表中可用的字母,其可以随后“生成”以生成排列。通过访问根节点,从该节点中的可用字母中选择一个随机字母,然后遍历该引用到下一个节点,开始生成排列。每次遍历时,都会为排列生成一个字母。当到达叶子时(即完全构造了一个排列),你将向后追溯树以查看父节点是否剩余任何可用的排列;如果没有,则可以修剪父节点。

作为实现细节,节点可以存储在该点无法生成的字母集或者仍然可以在该点生成的字母集。为了可能降低存储要求,您还可以允许节点存储 ,并带有一个标志,指示它正在执行的操作,以便当节点允许超过字母表的一半时,它会存储到目前为止生成的字母和当不到一半的字母可用时,切换到使用剩余的字母。

使用这样的树结构限制了可以生成的内容,而无需预先生成所有组合,因为您不需要预构建整个树(它可以在生成排列时构造)并且您可以保证由于节点的清除而完成(即,当只有一个允许的组合用于非生成的排列时,你只遍历到节点的链接)。

我相信这项技术的随机化有点奇怪,但我并不认为每种组合都可能在任何特定时间生成,尽管我并没有真正考虑过这一点。同样值得注意的是,即使完整的树不一定是预先生成的,所涉及的开销也可能足够大,以便您可以更好地预先生成所有排列。

答案 1 :(得分:0)

我认为你可以通过根据你拥有的字母表(在c#中)生成随机字符数组来做一些相当简单的事情:

        char[] alphabet = {'a', 'b', 'c', 'd'};
        int wordLength = 3;

        Random rand = new Random();

        for (int i = 0; i < 5; i++)
        {
            char[] word = new char[wordLength];
            for (int j = 0; j < wordLength; j++)
            {
                word[j] = alphabet[rand.Next(alphabet.Length)];
            }
            Console.WriteLine(new string(word));
        }

显然,这可能会产生重复,但您可以将结果存储在哈希映射中,或者根据需要检查重复项。

答案 2 :(得分:0)

所以我认为你想要的是使用尽可能少的内存来产生集合的排列。

首先,不能使用无记忆来完成。对于您的第一个字符串,您需要一个能够生成具有相同可能性的任何字符串的函数。假设该函数被称为nextString()。如果再次调用nextString()而不更改状态中的任何内容,当然它将再次能够生成任何字符串。

所以你需要存储一些东西。问题是,你需要存储什么,以及需要多少空间?

字符串可以看作数字0 - X ^ Y. (aaa = 0,aab = 1,aac = 2 ... aba = X ...)因此,为了尽可能有效地存储单个字符串,您需要lg(X ^ Y)位。假设X = 16且Y = 2。然后你需要1个字节的存储来唯一地指定一个字符串。

当然,最天真的算法是在生成时标记每个字符串,这需要X ^ Y位,在我的例子中是256位(32字节)。这就是你所说的你不想做的事情。你可以使用这个问题中讨论的shuffle算法:Creating a random ordered list from an ordered list(你不需要在通过shuffle算法生成字符串时存储字符串,但你仍然需要标记它们。)

好的,现在的问题是,我们能做得更好吗?我们需要存储多少,总计?

好吧,在第一次通话时,我们不需要任何存储空间。在第二次调用时,我们需要知道之前生成了哪一个。在最后一次通话中,我们只需要知道哪一个是最后一个。所以最糟糕的情况是我们已经过了一半。当我们走到一半时,已经产生了128个字符串,并且有128个字符串。我们需要知道剩下哪些产品。假设该过程是真正随机的,则可以进行任何拆分。有(256选128)可能性。为了能够存储任何这些,我们需要lg(256选128)位,根据谷歌计算器是251.67。因此,如果你真的很聪明,你可以将信息压缩到比天真算法少4位。可能不值得。

如果您只想让它看起来随意而只有很少的存储空间,请看这个问题:Looking for an algorithm to spit out a sequence of numbers in a (pseudo) random order