Java 如何洗牌一个没有两个相邻重复的字符数组?
我在一次采访中被问到这个问题: 如何洗牌一个没有两个相邻重复的字符数组 我提出的算法是:Java 如何洗牌一个没有两个相邻重复的字符数组?,java,arrays,algorithm,duplicates,shuffle,Java,Arrays,Algorithm,Duplicates,Shuffle,我在一次采访中被问到这个问题: 如何洗牌一个没有两个相邻重复的字符数组 我提出的算法是: 拥有字符的HashMap,字符对的出现计数。 通过此项查找重复元素与唯一元素的计数 如果duplicate>unique,则无法形成没有2的无序数组 相邻的重复元素(?) 如果unique>=duplicate,则有2个堆栈-1个包含unique 字符和包含重复字符的字符。构建 以从唯一堆栈中弹出元素的方式生成数组 首先,然后从复制堆栈中弹出一个元素。重复 例如: [a,b,b,c] shuffled ar
HashMap
,字符对的出现计数。
通过此项查找重复元素与唯一元素的计数[a,b,b,c] shuffled array with above algorithm - [a,b,c,b];
[b,b,b,c] unique < duplicate return error
[a,b,b,c]采用上述算法的洗牌数组-[a,b,c,b];
[b,b,b,c]唯一<重复返回错误
但我很确定我把逻辑复杂化了。有没有更简单、更简单的方法可以做到这一点?这本质上是一个排序问题。它让我想起了“峰值发现”,但反过来说,你想在某种意义上“创造独特项目的峰值” (2)的逻辑也有点错误。如果我有N个重复的字母,我仍然可以没有另一个字母的N-2的类似邻居:
'aaabb' -sort-> 'ababa'
这也说明了寻找“uniques”的问题,因为您很可能只有在数组中某个位置重复的字母
伪:
foreach letter in string{
if next != self then happy, move to next
if next == self,
loop until spot != self and swap
也许有一种更好的分而治之的方法可以在更好的时间完成它,但如果不进行实际测试,我不确定。[正如评论中指出的,有一个测试用例失败了]
因此,如果参考我的答案,请注意同样的问题
我明白了,但是如果你有'a'->4,'b'->2和'c'->1,它似乎不起作用。因为第一步是“abc”,留下'a'->3'b'->1。但答案是:“阿巴巴卡”——用户3386109 案例1:构建基本算法
'a'--> 4
'b'--> 3
'c'--> 3
'd'--> 2
这里我们有一桶大小相同的b和c。当出现这种情况时,我们必须对JoinBucket执行操作,它将在单个bucket中连接“b”和“c”,而“bc”将被视为单个元素
现在我们的水桶将是
'a'--> 4
'bc'--> 3
'd'--> 2
现在以与案例1相同的方式继续,我们尝试构建结果
=>result=“abcd”
=>result=“abcdabcd”
=>result=“abcdabcdabc”
=>Final Result=“abcdabca”我将从一个非常简单的算法开始:
public static void shuffleWithoutRepetition(char[] chars, Random rnd) {
if (tooManySameCharacters(chars))
throw new IllegalArgumentException("Too many same characters");
do {
shuffle(chars, rnd); // See java.util.Collections.shuffle
} while (containsRepetition(chars));
}
这样,您就有了一些工作代码,当它变得太慢时,您可以稍后对其进行优化
- 这个算法对于洗牌
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
- 它以相同的概率生成每个可能的输出,这很好
- SCALA代码。复制并粘贴此程序并运行
def rearrange(xs : List[Char]) : List[Char] ={
xs match {
case Nil => Nil
case x :: xs1 => xs1 match {
case Nil => x :: Nil
case y :: ys1 =>
if (x == y) {
(x :: rearrange(ys1)) :+ y
}
else
x :: y :: rearrange(ys1)
}
}
}
rearrange: (xs: List[Char])List[Char]
rearrange("hello".toList)
如果您有abcabc,您可以将其随机移动到例如cbacab。因此(2)中的测试具有假阳性。但是,如果没有足够的独特元素,那么(3)中的过程就无法工作。看看我对这个类似问题的回答是否有用:洗牌与排序的不同之处在于,它应该每次都产生不同的结果,而在理想世界中,所有可能的不同结果的可能性都是相同的。您可以随机洗牌字符串,然后尝试按照您的算法修复它,但(1)您的算法不起作用,(2)它将优先于某些排列。它不起作用,因为你可能需要从自我的两面寻找一个新的地方,所以你需要检查这个新地方没有“自我”邻居。是的,我知道它并不完美。谢谢你的反馈。我不确定我是否理解算法。对于
aaaabbc
,这将如何工作?我们的桶按发生顺序排列如下:aaa、bb、c。。。我们可以继续做“abc”,然后桶状态:aa,b,现在我们继续做“abcab”,新的桶状态:a,我们最后继续做“abcaba”。。。我已经编辑了我的答案以便更好地理解。我明白了,但是如果你有'a'->4,'b'->2和'c'->1,它似乎不起作用。因为第一步是“abc”,留下'a'->3'b'->1。但是有一个答案:“阿巴巴卡”。同意!!我会修改我的答案。。。我会花一些时间,但很快就会做:)感谢这个测试用例,我想你可以选择一个值最高的,然后选择一个值第二高的。把它们放进去,反复迭代,直到一个也不剩。在a4,b2,c1的情况下。我们构造“ab”,左a3,b1,c1。然后是“abab”,左a2,b0,c1。然后是“ababac”,左a1、b0、c0。然后是“阿巴巴卡”。对于A4B3CD2案例,我们有“ab”,a3b2c3d2,“abac”,a2b2c2d2,“abacab”,a1b1c2d2,“abacabcd”,a1b1c1d1,“adacabcdabcd”,都很好。
'a'--> 1
'bc'--> 0
'd'--> 0
public static void shuffleWithoutRepetition(char[] chars, Random rnd) {
if (tooManySameCharacters(chars))
throw new IllegalArgumentException("Too many same characters");
do {
shuffle(chars, rnd); // See java.util.Collections.shuffle
} while (containsRepetition(chars));
}
def rearrange(xs : List[Char]) : List[Char] ={
xs match {
case Nil => Nil
case x :: xs1 => xs1 match {
case Nil => x :: Nil
case y :: ys1 =>
if (x == y) {
(x :: rearrange(ys1)) :+ y
}
else
x :: y :: rearrange(ys1)
}
}
}
rearrange: (xs: List[Char])List[Char]
rearrange("hello".toList)