Java 如何在没有相邻相等元素的情况下随机排列字符串
因此,我有一个像“aaabbc”这样的示例字符串,我想随机洗牌它,但结果中没有两个连续的字母是相同的。输出应为“abababc”或“CBABAB”或“ABABAB”等 我尝试了一个使用PriorityQueue的代码,它解决了这个问题,但是只有一种方法没有随机生成许多方法来洗牌我的字符串,没有两个连续的。下面是我使用过的代码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
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的算法),直到结果与您的条件匹配(或返回起始点)
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,但那不是我想要的。感谢随意地洗牌而不重复是一个困难的问题。请参阅我链接的类似问题。有不同的解决方法,但我认为您已经开始的方法无法扩展到工作中。因此,我建议你结束这个问题,在阅读相关答案中的解决方案后重新开始。