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