Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/324.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何在没有相邻相等元素的情况下随机排列字符串_Java_Algorithm_Random_Permutation - Fatal编程技术网

Java 如何在没有相邻相等元素的情况下随机排列字符串

Java 如何在没有相邻相等元素的情况下随机排列字符串,java,algorithm,random,permutation,Java,Algorithm,Random,Permutation,因此,我有一个像“aaabbc”这样的示例字符串,我想随机洗牌它,但结果中没有两个连续的字母是相同的。输出应为“abababc”或“CBABAB”或“ABABAB”等 我尝试了一个使用PriorityQueue的代码,它解决了这个问题,但是只有一种方法没有随机生成许多方法来洗牌我的字符串,没有两个连续的。下面是我使用过的代码 int n = str.length(); int[] count = new int[MAX_CHAR]; for (int i = 0; i

因此,我有一个像“aaabbc”这样的示例字符串,我想随机洗牌它,但结果中没有两个连续的字母是相同的。输出应为“abababc”或“CBABAB”或“ABABAB”等

我尝试了一个使用PriorityQueue的代码,它解决了这个问题,但是只有一种方法没有随机生成许多方法来洗牌我的字符串,没有两个连续的。下面是我使用过的代码

    int n = str.length();
    int[] count = new int[MAX_CHAR];

    for (int i = 0; i < n; i++) {
        count[str.charAt(i) - 'a']++;
    }

    PriorityQueue<Key> pq = new PriorityQueue<>(new KeyComparator());
    for (char c = 'a'; c <= 'z'; c++) {
        int val = c - 'a';
        if (count[val] > 0) {
            pq.add(new Key(count[val], c));
        }
    }
    str = "";

    Key prev = new Key(-1, '#');
    while (pq.size() != 0) {
        Key k = pq.peek();
        pq.poll();
        str = str + k.ch;

        if (prev.freq > 0) {
            pq.add(prev);
        }

        (k.freq)--;
        prev = k;
    }

    if (n != str.length()) {
        return "";
    } else {
        return str;
    }
int n=str.length();
int[]计数=新的int[MAX_CHAR];
对于(int i=0;i0){
pq.添加(上一页);
}
(k.freq)--;
prev=k;
}
如果(n!=str.length()){
返回“”;
}否则{
返回str;
}

当我试图用那个算法随机生成它时,我被卡住了。我想要的结果是如上所述的动态输出。谢谢

假设您希望有效排列的分布相等: 如果您不关心内存或运行时的复杂性,则可以生成字符串()的所有排列,然后删除所有具有相邻相同字母的字符串,最后从该列表中随机选择一个

如果您确实关心优化内存或运行时,请参阅链接的类似问题

如果您不需要相等的分布,但仍有机会找到任何有效排列,请使用其他方法:

  • 您可以通过从剩余字母中随机选取来构建字符串(与您所做的类似),并在遇到死角时回溯(没有有效的字母可供选取)。看
  • 您可以创建一个字符串,从输入中选择随机字母,而不考虑相邻的重复,然后以迭代方式交换随机起始点(请参见Heap的算法),直到结果与您的条件匹配(或返回起始点)
回溯解 这里我选择一个随机的nextChar,并尝试构建一个不以该字符开头的随机字符串。如果失败,尝试另一个。通过递归,它最终会以随机顺序尝试所有组合,直到找到一个有效的组合

private static final Random RANDOM = new Random();

public static void main(String[] args) {
    System.out.println(randomPerm("aaabcc"));
}

public static String randomPerm(String str) {
    Map<Character, Long> counts = str
            .chars()
            .mapToObj(c -> (char) c)
            .collect(groupingBy(Function.identity(), Collectors.counting()));
    return restPerm(null, counts);
}

public static String restPerm(Character previous, Map<Character, Long> leftover) {
    List<Character> leftKeys = new ArrayList<>(leftover.keySet());
    while (!leftKeys.isEmpty()) {
        Character nextChar = leftKeys.get(RANDOM.nextInt(leftKeys.size()));
        leftKeys.remove(nextChar);
        if (nextChar.equals(previous) || leftover.get(nextChar) == 0) {
            continue; // invalid next char
        }
        // modify map in place, reduce count by one
        Long count = leftover.compute(nextChar, (ch, co) -> co - 1);
        if (leftover.values().stream().noneMatch(c -> c > 0)) {
            return nextChar.toString();  // last char to use
        }
        String rest = restPerm(nextChar, leftover); // recurse
        if (rest != null) {
            return nextChar + rest; // solution found
        }
        leftover.put(nextChar, count + 1);
    }
    return null;
}
private static final Random Random=new Random();
公共静态void main(字符串[]args){
系统输出打印LN(randomPerm(“aaabcc”);
}
公共静态字符串randomPerm(字符串str){
地图计数=str
.chars()
.mapToObj(c->(char)c)
.collect(groupby(Function.identity(),collector.counting());
返回restPerm(空,计数);
}
公共静态字符串restPerm(字符前一个,映射剩余){
List leftKeys=newarraylist(leftover.keySet());
而(!leftKeys.isEmpty()){
Character nextChar=leftKeys.get(RANDOM.nextInt(leftKeys.size());
leftKeys.remove(nextChar);
if(nextChar.equals(previous)| | leftover.get(nextChar)==0){
continue;//下一个字符无效
}
//就地修改地图,将计数减少1
Long count=leftover.compute(nextChar,(ch,co)->co-1);
if(剩余的.values().stream().noneMatch(c->c>0)){
返回nextChar.toString();//要使用的最后一个字符
}
字符串rest=restPerm(nextChar,剩余);//递归
if(rest!=null){
返回nextChar+rest;//找到解决方案
}
剩余物。放置(下一步,计数+1);
}
返回null;
}

此解决方案更有可能找到在结果开头使用稀有字符的结果,因此分布不相等。例如,输入“aaaaaaaabbbbb c”在左侧比右侧更常见,例如50%的情况下为“acabababab”。但它使用有限的内存,可能在计算所有排列之前完成,并且与您的方法有些类似。

您是否只需要使用
优先级队列
?请描述您的要求。在示例中,是否需要基于与种子字符串匹配的字母组合生成随机字符串?如果没有,您可以使用guid。如果您有其他技术,请向我咨询。但在本例中,我已经有了一个字符串要生成,没有两个consequentive。@AliRezaDehdar在本例中,我已经有了一个字符串,我希望它没有两个连续的字符串。我已经完成了,但我需要让它充满活力。我知道guid,但那不是我想要的。感谢随意地洗牌而不重复是一个困难的问题。请参阅我链接的类似问题。有不同的解决方法,但我认为您已经开始的方法无法扩展到工作中。因此,我建议你结束这个问题,在阅读相关答案中的解决方案后重新开始。