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
    ,字符对的出现计数。 通过此项查找重复元素与唯一元素的计数
  • 如果duplicate>unique,则无法形成没有2的无序数组 相邻的重复元素(?)
  • 如果unique>=duplicate,则有2个堆栈-1个包含unique 字符和包含重复字符的字符。构建 以从唯一堆栈中弹出元素的方式生成数组 首先,然后从复制堆栈中弹出一个元素。重复
  • 例如:

    [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:构建基本算法

  • 使用hashmap(键为字符,发生率为值)计算发生率。这将给我们提供类似于“cbaaba”的存储桶,将提供3个存储桶,其中“c”的值为1,“a”的值为3,“b”的值为2

  • 首先根据发生率最高的元素的发生率对桶进行排序。 现在我们有了

  • ‘a’->3,‘b’->2,‘c’->1

  • 从最大发生率桶中获取元素,在映射中将其计数减少1,并将其放入结果数组中。根据已排序的发生桶,后续发生桶请遵循此操作
  • 结果数组将以排序方式从3个桶中各取一个开始

    “abc”现在我们的桶是'a'->2',b'->1和'c'->0

    接下来,我们再次尝试从已排序的bucket中获取elemet(忽略包含0个元素的bucket)

    “abcab”现在我们的桶状态变成:'a'->1,'b'->0和'c'->0

    下一步,如上所述,我们继续将结果作为

    =>“阿布卡巴”

    案例2:如果字符串类似于“aaaabbbcccdd”

    我们将有水桶作为食物

    '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)