如何在O(n * log K)时间内对平均长度为K的排序列表进行排序?
答案 0 :(得分:6)
正如您对问题的评论中所提到的,O(nlog(k))是不可能的,但是this page上的一些算法可以有效地完成您的任务;这是一个:
获取每个列表的第一个元素 并创建一个堆(大小为k)。弹出 最小的元素。从中找到数组 元素来了(让我们说它来了 从列表编号i)。拿下一个 列表i中的元素并将其推入 堆。对于进入的每个元素 合并列表,我们花了log(k)时间。所以 时间复杂度是O(N * logk)在哪里 N是元素的总数 所有的K列表。
- 写作:Abhishek Goyal
答案 1 :(得分:0)
合并排序是关键。让我们假设N是要统一的元素总数,K是包含它们的容器数:
将所有已排序的序列追加到单个向量中,但要记住添加它们的位置。更好的是,如果你按照第一个元素的值对它们进行排序,会加快下一步的速度。
然后合并已排序的序列对(如果使用C ++,则为std :: inplace_merge)。每个合并都是Na + Nb,所以每一步都是N.你必须执行logK步骤。
因此NlogK。
答案 2 :(得分:0)
我相信有可能达到O(N * log(K)),但在最坏的情况下则不行。
考虑对这些列表进行排序:
{0,1,2,3,4,5,6,7,8,9,10},
{10,11,12,13,14,15,16,17,18,19,20},
{20,21,22,23,24,25,26,27,28,29,30}
我的人脑可以轻松地对这些列表进行排序,而无需读取每个值,因此应该有一个算法可以做同样的事情。我们需要在使用修改的二进制搜索时进行合并以查找值的范围。
在最坏的情况下,你得到O(N * K),因为必须比较每个值。例如:
{0,2,4,6,8},
{1,3,5,7,9}
这是我在Go中的解决方案,如果我知道排序列表通常具有相对于K的小重叠区域,我将只使用它:
// variation of binary search that finds largest
// value up to and including max
func findNext(a []int, imin int, vmax int) int {
imax := len(a) - 1
best := -1
for imin <= imax {
imid := imin + ((imax - imin) / 2)
if a[imid] == vmax {
return imid
} else if a[imid] < vmax {
best = imid
imin = imid + 1
} else {
imax = imid - 1
}
}
return best
}
func sortNSortedLists(in [][]int) []int {
var out []int
cursors := make([]int, len(in))
for {
// Find the array indices that have the smallest
// and next to smallest value (may be same) at
// their current cursor.
minIdx1 := -1
minIdx2 := -1
minVal1 := math.MaxInt32
minVal2 := math.MaxInt32
for i, cursor := range cursors {
if cursor >= len(in[i]) {
continue
}
if in[i][cursor] < minVal1 {
minIdx2 = minIdx1
minVal2 = minVal1
minIdx1 = i
minVal1 = in[i][cursor]
} else if in[i][cursor] < minVal2 {
minIdx2 = i
minVal2 = in[i][cursor]
}
}
if minIdx1 == -1 {
// no values
break
}
if minIdx2 == -1 {
// only one array has values, so append the
// remainder of it to output
out = append(out, in[minIdx1][cursors[minIdx1]:]...)
break
}
// If inVal1 is smaller than inVal2,
// append to output all values from minVal1 to minVal2 found in
// the minIdx1 array, and update the cursor for the minIdx1 array.
if minVal1 < minVal2 {
firstCursor := cursors[minIdx1]
lastCursor := findNext(in[minIdx1], firstCursor, minVal2)
if lastCursor != -1 {
out = append(out, in[minIdx1][firstCursor:lastCursor+1]...)
cursors[minIdx1] = lastCursor+1
continue
}
}
// Append the single value to output
out = append(out, minVal1)
cursors[minIdx1]++
}
return out
}
答案 3 :(得分:-2)
您可以调整合并排序来完成工作。合并排序利用将已排序列表合并到新排序列表中的简便性。