我不确定这是否有帮助(甚至是愚蠢的),但我想到了这一点:
您使用排序功能对网格中的所有元素进行排序,然后选择第一个k
元素。如果您考虑像递归合并排序这样的排序算法,您会得到这样的结果:
- 将集合分成两半
- 递归两半
- 合并两个排序的一半
也许您可以根据需要优化这样的功能。合并部分通常会合并两半的所有元素,但您只对k
合并产生的第一个元素感兴趣。所以你只能合并直到你有k
元素并忽略其余部分。
所以在最坏的情况下,其中k >= n
(n
是网格的大小)你仍然只有合并排序的复杂性。O(n log n)
老实说,我无法确定此解决方案相对于k
. (此刻太累了)
这是该解决方案的示例实现(绝对不是最佳的,也不是通用的):
def minK(seq: IndexedSeq[coord], x: coord, k: Int) = {
val dist = (c: coord) => c.dist(x)
def sort(seq: IndexedSeq[coord]): IndexedSeq[coord] = seq.size match {
case 0 | 1 => seq
case size => {
val (left, right) = seq.splitAt(size / 2)
merge(sort(left), sort(right))
}
}
def merge(left: IndexedSeq[coord], right: IndexedSeq[coord]) = {
val leftF = left.lift
val rightF = right.lift
val builder = IndexedSeq.newBuilder[coord]
@tailrec
def loop(leftIndex: Int = 0, rightIndex: Int = 0): Unit = {
if (leftIndex + rightIndex < k) {
(leftF(leftIndex), rightF(rightIndex)) match {
case (Some(leftCoord), Some(rightCoord)) => {
if (dist(leftCoord) < dist(rightCoord)) {
builder += leftCoord
loop(leftIndex + 1, rightIndex)
} else {
builder += rightCoord
loop(leftIndex, rightIndex + 1)
}
}
case (Some(leftCoord), None) => {
builder += leftCoord
loop(leftIndex + 1, rightIndex)
}
case (None, Some(rightCoord)) => {
builder += rightCoord
loop(leftIndex, rightIndex + 1)
}
case _ =>
}
}
}
loop()
builder.result
}
sort(seq)
}