生成所有可能的字符串优化

时间:2017-03-17 18:56:57

标签: java string loops random while-loop

我必须生成一个可能的每个字符串的列表(给定一个特定的字符串来从中挑选字符),我想出的第一个方法就是这个:

public String getRandomLetters(Integer size, String range){
    String word = "";
    Random r = new Random();

    for (int i = 0; i < size; i++) {
        word += range.charAt(r.nextInt(range.length()));
    } 

    return word;
}

像这样使用:getRandomLetters(2, "abc");

这将返回一个包含2个字母的字符串。

现在,有了这个给定的范围,我必须生成一个随机字符串列表。这个单词列表必须没有可重复的单词,必须以1个字符开头,当有可能时只添加另一个单词。

我试着这个:

public List<String> getListOfRandomWords(Integer listLenght){
    String range = "abc"; //abcdefghijklmnopqrstuvwxyz
    Integer rangeLenght = range.length();

    List<String> words = new ArrayList();
    int counter = 1;

    int possibilities = (int) Math.pow(Double.valueOf(rangeLenght), Double.valueOf(counter));

    String word = "";

    for (int i = 0; i < listLenght; i++) {
        word = getRandomLetters(counter, range);

        while (words.contains(word)) {
            if(words.size() == possibilities){
                counter++;
                possibilities += (int) Math.pow(Double.valueOf(rangeLenght), Double.valueOf(counter));
            }
            word = getRandomLetters(counter, range);
        }

        words.add(word);
    }

    return words;
}

运行此:

        List<String> testList = getListOfRandomWords(20);

        for (String block : testList) {
            System.out.println(block);
        }

输出:

c
b
a
cc
ca
aa
bb
ba
ac
bc
ab
cb
bcc
cca
bac
aab
bab
cbb
baa
bcb

输出正常且方法正常,我唯一关心的是while(randomLetters.contains(randomLetter)),这是检查重复值的最佳方法吗?

PD:我不能使用和来使这更容易并按顺序生成字符串,它们必须按随机顺序排列。

3 个答案:

答案 0 :(得分:0)

使用List<String> words = new ArrayList<>();words.contains(word)绝对不是检查重复值的最佳方式。这是一个O(N²)操作,因为你对每个单词进行了O(N)搜索,并且对于你添加的每个单词都要循环一次或多次。

Set<String> words = new HashSet<>();words.contains(word)应该明显加快。

当然,如果您想维护您添加了单词的顺序,而不是一些随机顺序,那么您需要使用:Set<String> words = new LinkedHashSet<>();

使用return new ArrayList<>(words)将返回的值转换回List<String>

答案 1 :(得分:0)

我发现循环遍历所有排列的最佳方式是Heap's algorithm

我完全不理解它,因为我没有阅读它背后的证据,但它绝对有效,并且只需要在所有排列中循环一次。使用随机置换生成器永远不能保证生成所有排列。

答案 2 :(得分:0)

Random和Unique不能一起满足。因此,假设您需要所有排列的随机 order

如果字符串的长度相对较小(因此结果列表适合内存),您可以先生成所有排列,然后再生成随机播放结果。这将提供相当不错的性能,因为两个操作在输出大小上是线性的。

获取代码组合Smart way to generate permutation and combination of StringRandom shuffling of an array

如果一次只需要一个随机唯一结果 - 生成随机字符串的原始代码是可以的,但您应该使用Hashset或类似结构来查找重复项(Fastest data structure for contains() in Java?)。

请注意,以这种方式生成所有组合是不切实际的 - 在大约80%的组合之后,重试次数将增长得非常大,并且最终会接近所有组合的数量。

或者,您可以直接将随机数转换为字符串:

  1. 生成从1到(numberOfCharacters ^ LengthOfString)的随机数,
  2. 检查Hashset中是否有重复 - 返回1
  3. 为Hashset添加号码
  4. 将数字转换为字符串(除以numberOfCharacters直到达到0并在每一步使用提醒选择字符)
    19为“abc”:
    19/3 = 6,提示1 - 在结果中添加“b” 6/3 = 2,提醒0 - 在结果中添加“a” 2 - 将“c”添加到result =“bac”