在n个项的数组中找到k个最小数的算法

Jes*_*ica 24 arrays algorithm selection

我正在尝试编写一种算法,该算法可以在O(n)时间内打印n个大小数组中的k个最小数字,但我无法将时间复杂度降低到n.我怎样才能做到这一点?

Che*_*het 41

我之前在接受采访时已经这样做了,其中一种最优雅/最有效的方法就是这样做

O(n log k). 
with space: O(k) (thanks, @Nzbuu)
Run Code Online (Sandbox Code Playgroud)

基本上你将使用大小限制为k的最大堆.对于数组中的每个项目,检查它是否小于最大值(仅O(1)).如果是,则将其放入堆中(O(log k))并删除最大值.如果它更大,请转到下一个项目.

当然,堆不会产生k个项的排序列表,但这可以在O(k log k)中完成,这很容易.

类似地,您可以执行相同的操作来查找最大的k项,在这种情况下,您将使用最小堆.

  • +1.这就是我要做的.它也很容易实现,只需要O(k)空间. (2认同)

ami*_*mit 25

你需要使用'选择算法'找到第k个最小元素,即O(n),然后再次迭代数组并返回每个小于/等于它的元素.
选择算法:http ://en.wikipedia.org/wiki/Selection_algorithm
如果你有重复,你将不得不注意:你需要确保你没有返回更多的k元素(例如你有可能1,2,...,k,k,k,...)

编辑:
完整算法,并按要求返回一个列表:让数组为A

 1. find the k'th element in A using 'selection algorithm', let it be 'z'
 2. initialize an empty list 'L'
 3. initialize counter<-0
 4. for each element in A: 
 4.1. if element < z: 
   4.1.1. counter<-counter + 1 ; L.add(element)
 5. for each element in A:
 5.1. if element == z AND count < k:
   5.1.1. counter<-counter + 1 ; L.add(element)
 6. return L
Run Code Online (Sandbox Code Playgroud)

请注意,如果列表可能有重复项,则需要进行第3次迭代.如果它不能 - 它是不必要的,只需将4.1中的条件更改为<=.
还要注意:L.add正在向链表中插入一个元素,因此是O(1).


Jer*_*fin 5

假设您正在尝试显示K个最小数字,您可以使用Hoare选择算法来查找第k 最小数字.将数组划分为较小的数字,第k 数字和较大的数字.

  • +1,虽然要注意*Hoare的*quickselect算法不是O(n),但它有最坏的情况.固定版本称为"中位数中位数"方法,而不是Hoare. (8认同)

Tam*_*ash 0

只需使用归并排序对数组进行排序,然后打印前 k 个数字,在最坏的情况下将需要 n*log2(n) 。