【问题标题】:Generator of random words without repeating letters without searching生成随机单词而不重复字母而不搜索
【发布时间】:2021-06-05 15:21:44
【问题描述】:

传递给生成器的参数是什么:

  • x - 字数;
  • N 是字母的大小;
  • L 是输出字的长度。

需要实现一个非递归算法,根据传入的三个参数返回一个单词。

Alphabet - 按字母顺序排列的拉丁字母,大写。

对于N = 5, L = 3,我们构造了x与单词的对应关系:

  • 0:ABC
  • 1:ABD
  • 2:安倍
  • 3:ACB
  • 4: ACD
  • 5:王牌
  • 6:亚行
  • 7:ADC
  • 8 ADE
  • 9:自动包围曝光
  • 10 AEC
  • 11 迪拉姆
  • 12 BAC
  • ...

我的算法实现适用于 L = 1; 2. 但是 L = 3 出现错误。该算法基于访问字母表时的移位。 h 数组存储新字典中字母的索引(已输入单词的字符被排除在外)。数组A 将索引转换h 存储到原始字典中(为从字母表中删除的每个字符添加缩进到左侧)。因此,最后,数组A 存储了没有重复的排列。

private static String getS (int x, int N, int L) {
    String s = "ABCDEFGHJKLMNOPQ";
    String out = "";

    int [] h = new int [N];
    int [] A = new int [N];

    for (int i = 0; i <L; i ++) {
        h [i] = (x / (factory (N - 1 - i) / factory (N - L)))% (N-i);

        int sum = h [i];

        for (int j = 0; j <i; j ++)
            sum + = ((h [i]> = h [j])? 1: 0);
        
        A [i] = sum;
        out + = s.charAt (A [i]);

    }

    return out;
} 

【问题讨论】:

  • 您的标题与您的描述不符。您需要一个随机单词,还是按字母顺序排列的第 x 个单词?
  • @Dave 可能是的。我的意思是 x 是随机的,但对于每个 x 有一个单词

标签: algorithm random generator permutation combinatorics


【解决方案1】:

要生成一个长度为 L 的随机词:将字母表保存在一个大小为 N 的数组中,并通过将第 i 个元素与 i 中的随机元素交换为 N-1 来获取长度为 L 的随机词[0, L-1]。

要按字母顺序生成长度为 L 的第 x 个单词:请注意,对于由大小为 N 的字母表中的不同字母组成的大小为 L 的单词,有 (N-1) 个! /(N-L)!以任何给定字母开头的单词。

例如,N=5,L=3,字母表 = ABCDE。以 A(或任何字母)开头的单词数为 4! /2! = 12。这些都是可用 N-1 个字母的有序 N-L 长度子集。

所以 word(x, N, L) 的第一个字母是字母表中的 x / ((N-1)! / (N-L)!) 字母(零索引)。

然后您可以递归地构建您的单词。

例如,word(15, 5, 3, ABCDE):第一个字母是 15 / (4! / 2!) = 15 / 12) = 1,所以 B。

我们递归地得到第二个字母: word((15 % (4! / 2!), 4, 2, ACDE) = word(3, 4, 2, ACDE)。因为 3 / (3! / 2! ) = 3 / 3 = 1,第二个字母是C。

第三个字母:word(3%3, 3, 1, ADE) = word(0, 3, 1, ADE) = A.

0. ABC
1. ABD
2. ABE
3. ACB
4. ACD
5. ACE
6. ADB
7. ADC
8. ADE
9. AEB
10. AEC
11. AED
12. BAC
13. BAD
14. BAE
15. BCA

【讨论】:

  • 感谢您的回答!我认为这可能是解决方案,但我担心我们无法在没有递归的情况下通过代码实现它......
  • @D7ILeucoH 您可以保留一组迄今为止使用过的字母,而不是递归,并通过遍历字母表来获取第 k 个字母,跳过使用过的字母。这增加了 O(N*L),但如果 L 是有界的(例如
  • 我的解决方案实际上是在一个新的字母表中计算正确的索引。但是将此索引转换为初始字母表的索引存在问题
【解决方案2】:

另一种方法。您有一个包含五个字母的列表:[ABCDE],并且您有一些由其中三个字母组成的单词,没有重复。因此,每个字母要么包含(1),要么不包含(0)。这将每个单词映射到一个只有三位设置的五位整数。更一般地说,您将每个单词映射到设置了 N 位的 L 位整数。

这建议遍历 L 位整数,计算设置位的数量。跟踪设置了 N 位的整数的数量。当您到达所需位置时,将整数翻译回一个单词:22 -> 10110 -> ACD。

如果简单的方法不够快,有多种技巧可以使用一些逻辑运算来加速设置位的计数。

ETA:我应该明确表示您以相反的顺序从 0b11111 向下扫描到 0b00000。这与字母顺序相匹配。 ABC (11100) 在 CDE (00111) 之前。

【讨论】:

  • 它可能很快,但它不是解决方案。创建地图很糟糕,10110 忽略了任何其他字母组合
  • 您没有忽略任何相关组合。只有字母数量正确的组合才会被计算在内。订购时请查看我的预计到达时间。
猜你喜欢
  • 1970-01-01
  • 2015-07-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-13
  • 1970-01-01
相关资源
最近更新 更多