排序列表,以便相等元素之间的差距尽可能大

时间:2015-08-26 10:39:41

标签: algorithm scala sorting

让我们假设我有一个未分类的List包含a, a, b, b, a, c,我想要对这个序列进行排序,以便相等元素之间的间隙尽可能大。因此,在此样本序列的情况下,可能的输出可能是b, a, c, a, b, a。在我的应用中,间隙达到其精确的平均最大值并不重要,但是只要有可能,就不应该是彼此相邻的两个相等的元素。所以我的压力是最大化最小的差距。

2 个答案:

答案 0 :(得分:1)

正如评论者所说,没有独特的解决方案,因为它取决于您的成本函数。我的想法是沿着以下一行,只查找正确的邻居,如果没有其他相同的元素,则为他们分配list.size分数:

def maxGaps[A](in: List[A]): List[A] = {
  if (in.isEmpty) return in

  def noPairs(xs: List[A]): Boolean =
    xs.sliding(2, 1).forall { case List(a, b) => a != b }

  val (good, bad) = in.permutations.partition(noPairs)
  val candidates = if (good.nonEmpty) good else bad

  val maxDist = in.size

  def calcScore(xs: List[A], accum: Int = 0): Int =
    xs match {
      case head :: tail =>
        val i = tail.indexOf(head)
        val j = if (i < 0) maxDist else i
        calcScore(tail, accum + j)      
      case Nil => accum
    }

  candidates.maxBy(calcScore(_))
}

maxGaps("aabbac".toList) // abacab

答案 1 :(得分:1)

我从测量每个独特元素的频率开始:

scala> val l = List("a", "a", "b", "b", "a", "c")
l: List[String] = List(a, a, b, b, a, c)

scala> val in = l.toSet[String].map(x => x -> l.count(x==)).toList.sortBy(_._2).reverse
in: List[(String, Int)] = List((a,3), (b,2), (c,1))

所以现在你可以生成更多分散的列表:

def shuffle[T](l: List[T]) = {

   def fill(n: Int, l: List[List[T]], s: T) = 
      l.take(n + 1).reduce(_ ++ List(s) ++ _) ++ l.drop(n + 1).flatten

   val in = l.toSet[T].map(x => x -> l.count(x==)).toList.sortBy(_._2).reverse

   val initial = in.head._2 -> List.fill(in.head._2)(in.head._1)

   in.tail.foldLeft(initial){case ((size, acc), (value, count)) => 
     count -> fill(count, acc.grouped(acc.size / size).toList, value)
   }._2
}

scala> shuffle(l)
res32: List[String] = List(a, b, c, a, b, a)

此处的每个下一次迭代都基于前一个具有更高频率的迭代:尽可能宽地插入到列表中的元素(来自先前的迭代)。因此,如果频率在迭代之间显着下降,那么它可能不会那么有效,因为高频率元素可能不会被sc&#34; scrumbled&#34;足够。

该算法并未尝试最大化每个距离 - 它试图将分组元素外观的概率降至最低。只是随机改组应该做类似的事情,如果你用不太精确的结果很好,因为它产生的概率仍然很小但更高的组:

scala> scala.util.Random.shuffle(l)
res34: List[String] = List(a, b, c, b, a, a)