我正在努力完成我的家庭作业并需要一点推力 - 问题是设计一种算法,在O(nlogm)时间内找到多个最小元素1<k1<k2<...<kn
并且你有m * k。我知道一个简单的选择算法需要花费o(n)时间来找到第k个元素,但是如何减少重复中的m?我虽然在每次跑步中同时做k1和kn,但是这只会取2而不是m / 2。
会欣赏一些指示。 谢谢
答案 0 :(得分:2)
如果我正确理解了这个问题,你有一个包含m个索引的向量K,你想找到K中每个k的第k个排序元素。如果K包含最小的m个索引(即k = 1) ,2,...,m)那么这可以在线性时间T = O(n)中通过使用quickselect来轻松完成,以找到元素k_m(因为所有较小的元素将在quickselect的末尾位于左侧)。所以我假设K可以包含任何m个索引。
实现此目的的一种方法是同时在所有K上运行quickselect。这是算法
QuickselectMulti(A,K)
If K is empty, then return an empty result set
Pick a pivot p from A at random
Partition A into sets A0<p and A1>p.
i = A0.size + 1
if K contains i, then remove i from K and add (i=>p) to the result set.
Partition K into sets K0<i and K1>i
add QuickselectMulti(A0,K0) to the result set
subtract i from each k in K1
call QuickselectMulti(A1,K1), add i to each index of the output, and add this to the result set
return the result set
如果K只包含一个元素,则与随机化quickselect相同。要了解为什么运行时间平均为O(n log m),首先要考虑当每个枢轴精确地将A和K分成两半时会发生什么。在这种情况下,您将获得两个递归调用,因此您有
T = n + 2T(n/2,m/2)
= n + n + 4T(n/4,m/4)
= n + n + n + 8T(n/8,m/8)
由于每次m减半,因此n
将在此总和中显示log m
次。要实际获得预期的运行时间需要更多的工作,因为您不能假设数据透视表将两个数组分成两半,但如果您完成计算,您将看到运行时间实际上是O(n记录m)平均。
编辑时:通过运行p = Quickselect(A,k_i)选择枢轴可以使这个算法变得更简单,其中k_i是K的中间元素,而不是随机选择p。这将保证K每次都被分成两半,因此递归调用的数量将精确地为log m,并且由于quickselect以线性时间运行,因此结果仍为O(n log m)。