# finding smallest k elements in array in O(k)

This is an interesting question I have found on the web. Given an array containing n numbers (with no information about them), we should pre-process the array in linear time so that we can return the k smallest elements in O(k) time, when we are given a number 1 <= k <= n

I have been discussing this problem with some friends but no one could find a solution; any help would be appreciated!

quick notes: -the order of the k smallest elements is not important -the elements in the array are number , might be integers and might be not (so no radix sort) -the number k is not know in the pre-processing stage.the preprocessing is O(n) time. the function ( find k smallest elements) on O(k) time .

• How about using a min-heap? – Shir Jun 23 '13 at 14:44
• Look at k-skyband and top-k computation. The paper cs.sfu.ca/~jpei/publications/subsky_tkde07.pdf has a nice review of related literature. – András Salamon Jun 23 '13 at 14:44
• Shir-I have examined the min-heap idea . however , in order to print the k smallest numbers in min heap is in O(klogn) time and not O(k) as required – Idan Jun 23 '13 at 14:47
• @idannik: Why do you think it takes $\Omega(k \log n)$ time to find the $k$ smallest elements in a min-heap? – Kristoffer Arnsfelt Hansen Jun 23 '13 at 20:07
• I don't think this is research-level. It looks like an assignment. Where did you find it? – Kaveh Jun 23 '13 at 21:20

## Preprocess the array of $n$ values in time $O(n)$:

• $i\leftarrow n$
• while $i>2$
• Compute the median $m$ of $A[1..i]$ in time $O(i)$
• partition $A[1..i]$ into $A[1..i/2-1] \leq m$ and $A[i/2+1..i]\geq m$ in the same time.
• $i \leftarrow \lfloor i/2 \rfloor$

The total precomputation time is within $O(1+2+4+...+n)\subseteq O(n)$

## Answer a query for the $k$ smallest elements in $A$ in time $O(k)$:

• $l\leftarrow \lfloor \log_2 k \rfloor$
• select the $(k-2^l)$th element $x$ of $A[2^l..2^{l+1}]$ in time $O(2^l)\subseteq O(k)$
• partition $A[2^l..2^{l+1}]$ by $x$ in the same time

$A[1..k]$ contains the $k$ smallest elements.

## References:

• In 1999, Dor and Zwick gave an algorithm to compute the median of $n$ elements in time within $2.942 n + o(n)$ comparisons, which yields an algorithm to select the $k$th element from $n$ unordered elements in less than $6n$ comparisons.
• I guess the outer loop is supposed to be 'for i in $\{2^{\lceil\lg n\rceil},\dots,4,2,1\}$'. Is your algorithm different from the one in Yuval Filmus' answer? – Radu GRIGore Jun 23 '13 at 20:14
• This is a generalization of my algorithm to arbitrary $n$. It also spells out some implementation details which were (deliberately) left out from my answer. – Yuval Filmus Jun 23 '13 at 20:39
• @YuvalFilmus Do you wish to imply by your comment that my answer is unethically close to yours? This is the solution which came to mind when I reviewed the question. I saw that you posted a similar one, but found it unclear, so I wrote my own (as opposed to doing a major edit of yours). What matters ultimately is the quality of the answers on the systems, not really who wrote them: the badges and reputation are only incentives, not objectives in themselves. – Jeremy Jun 24 '13 at 12:28
• @Jeremy Not at all; Just that the two solutions are the same (but yours works for arbitrary $n$), and that I didn't flesh out the details in case it was actually a homework question. – Yuval Filmus Jun 24 '13 at 14:40
• Oh :( Sorry about that then. (Althought I would still think giving complete answers to be a priority over assignment suspicions) – Jeremy Jun 25 '13 at 13:31

Assume for simplicity that $n = 2^m$. Use the linear time selection algorithm to find the elements at positions $2^{m-1},2^{m-2},2^{m-3},\ldots,1$; this takes linear time. Given $k$, find $t$ such that $2^{t-1} \leq k \leq 2^t$; note that $2^t \leq 2k$. Filter out all elements of rank at most $2^t$, and now use the linear time selection algorithm to find the element at position $k$ in time $O(2^t) = O(k)$.

Clarification: It might seem that the preprocessing takes time $\Theta(n\log n)$, and that is indeed the case if you're not careful. Here is how to do the preprocessing in linear time:

while n > 0:
find the (lower) median m of A[0..n-1]
partition A in-place so that A[n/2-1] = m
n = n/2


The in-place partitioning is done like in quicksort. The running time is linear in $n + n/2 + n/4 + \cdots + 1 < 2n$, and so linear. In the end, the array $A$ satisfies the following property: for each $k$, $A[0..n/2^k-1]$ consists of the $n/2^k$ smallest elements.

• Naturally. If the array is sorted that you can solve this in $O(1)$ without preprocessing. Perhaps you are not aware of the linear time selection algorithm that can find the $k$th largest element in time $O(n)$? – Yuval Filmus Jun 23 '13 at 16:03
• @Yuval Filmus: Are you not running the algorithm $\log n$ times, for a total of $n \log n$ steps? Or did you have some kind of interleaving in mind? – András Salamon Jun 23 '13 at 17:12
• @AndrásSalamon: If you read the answer given by Jeremy (which looks to me almost the same as this one) you see that you first process the whole array, then the first half, and so on. – Radu GRIGore Jun 23 '13 at 20:20
• @AndrásSalamon Radu is correct. After you find the median, you partition the array (in-place) into its lower and upper half, then recurse on the lower half. The running time is then proportional to $n+n/2+n/4+\cdots+1 < 2n$. – Yuval Filmus Jun 23 '13 at 20:31
• Incidentally this algorithm appears as a subroutine in my answer to an earlier question: cstheory.stackexchange.com/questions/17378/… – David Eppstein Jun 23 '13 at 23:12

First use $$O(n)$$ to build a min-heap. It is known that we can use $$O(k)$$ to find the $$k$$ smallest elements in a min-heap:

Frederickson, Greg N., An optimal algorithm for selection in a min-heap, Inf. Comput. 104, No. 2, 197-214 (1993). ZBL0818.68065..

• I don't see how we can extract the smallest $k$ elements from a min-heap in time $O(k)$, as removing each element takes logarithmic time in the size of the heap. Could you clarify what you had in mind here? Thanks! – a3nm May 17 '19 at 13:59
• @a3nm It is indeed not a simple algorithm, but I've updated the reference. – hqztrue May 19 '19 at 13:36
• Sorry, as far as I can tell the reference that you added just talks about selecting the $k$-th smallest element (i.e., a single element, not the $k$ smallest elements) in time $O(k)$. I don't see how this would adapt to extracting the $k$ smallest elements. Could you maybe explain or update the reference? – a3nm May 27 '19 at 13:53
• @a3nm yes the reference only gives you the $k$-th smallest element $x$. However after knowing that, you can just perform a dfs in the heap to find all elements $<x$ in $O(k)$. – hqztrue May 27 '19 at 14:45
• Sorry I don't see which DFS you would perform to find these elements? (Some of them may not be ancestors of the $k$-th smallest element in the heap, i.e., as far as I can tell locating, e.g., the $k/2$-th element knowing the position of the $k$-th element is not trivial.) – a3nm May 28 '19 at 16:24

Use linear time selection to find the $k$th largest element, then do a partition step from quicksort using the $k$th largest element as the pivot.

• The original question mentions that $k$ is not known at preprocessing time.... – Jeremy Jun 23 '13 at 19:35
• I see. My mistake. – jbapple Jun 23 '13 at 22:17