This is a standard question which has been answered many a times in several sites but in this version there are additional constraints:
I am going to assume read-only array is a strong requirement, and try to find tradeoffs that do not violate it in this answer (So, using selection algorithm is not an option, since it modifies the array)
As a side note, from wikipedia, it cannot be done in O(1) space without modifying the array:
The required space complexity of selection is easily seen to be k + O(1) (or n − k if k > n/2), and in-place algorithms can select with only O(1) additional storage .... The space complexity can be reduced at the cost of only obtaining an approximate answer, or correct answer with certain probability
It can be done in O(k) space with O(nlogk) time. In case k
is constant, it is O(1)
solution
The idea is to keep a max heap of size k
. First populate it with the first k
elements, and then keep iterating the array. If some element x
is smaller than the top of the heap, pop the old head, and insert x
instead.
When you are done, the head of the heap is the k
th smallest element.
In terms of big O notation, it can be done in O(n)
with O(k)
space by using a new array of size 2k
, load elements in chunks to the array, and use selection algorithm on this auxillary array to find the k
th element. Discard all elements bigger than the k'th element, and repeat for next chunk (load more k
elements). Complexity is O(k*n/k) = O(n)
This is however seldom used and has significantly worse constants than the heap solution, which is used quite often.
If you really want to use O(1) space, a brute force solution can be used by finding a minimum k
times. You only need to remember the old minimum, which is constant space. This solution is O(nk)
time with O(1) space, which is significantly less efficient than the alternatives, in terms of time.