3

Given an array at the size of n give a deterministic algorithm (not quick sort) that uses O(1) space (not medians of medians) that will find the K'th smallest item.

There are the obvious solutions such as sorting the array on nlogn or finding the minimum k time in nk but I'm sure there is a better way of doing that. It doesn't have to be liner (I doubt it if it can).

Thanks for the helpers.

Ofer Magen
  • 832
  • 1
  • 8
  • 17

2 Answers2

4

Arrange (so that no extra space is wasted) the array into a min-heap (can be built in O(n) time) and then do k extract-min operations, each of whicih takes O(log n) time. So you have O(n + k*log n) time altogether. (Since k <= n the worst case is O(n log n).)

The space complexity is O(1) or, if you count the array that we've modified, O(n); but any algorithm will need the array and will thus need those O(n) space contributed by the array. The additional space cost incurred by the heap is O(1).

It's obvious that this approach is correct: the first extract-min returns (and removes from the heap) the smallest element; the second extract-min returns (and removes from the heap) the second-smallest element; ...; and the k-th extract-min returns (and removes from the heap) the k-th smallest element.

If k is "much bigger" than n/2 then you can speed things up by using max-heap and search for (n-k)-th largest element using similar approach.

Community
  • 1
  • 1
blazs
  • 4,352
  • 18
  • 36
0

I found BitVector another way of solving this problem.

Populating the BitVector requires O(n) time and finding an the k'th smallest element requires approximately O(k) time. Therefore the total complexity will be O(n).

Space complexity might be different according to each scenario. In my scenario, the list can contain an unsorted set of positive integers starting from 1 to 2147483647 (java.lang.Integer.MAX_VALUE) (2147483647/32 * 4 / 1024 / 1024 =~ 255 MB).

Here is my implementation in Java:

int findKthSmallestInUnsortedList(List<Integer> list, int k) {
    // Step 1: Populate (read) data from list to the bit-vector in O(n) time
    int[] bitVector = new int[Integer.MAX_VALUE/32]; //4 bytes chunks (int): 32 bits
    for(Integer num : list) {
        int chunkNum = num / 32;
        int indexInChunk = num % 32;
        bitVector[chunkNum] |= (1 << indexInChunk);
    }

    // Step 2: Find the k'th '1' starting from the first chunk in O(k) time
    int count = 0;
    for (int i = 0; i < bitVector.length; i++) {
        int bitCount = 0;
        while(bitVector[i] != 0) {
            if ((bitVector[i] & 1) != 0) {
                count++;
            }
            if (count == k) {
                return i * 32 + bitCount;
            }
            bitCount++;
            bitVector[i] >>= 1;
        }
    }
    return -1; // not found
}

For those who are not familiar with BitVector, here is an example:

Imagine number 4 is in the list. Therefore we set the 4th bit in the first chunk to 1:

00000000 00000000 00000000 00001000

If 33 is read, according to the above implementation, we go to the second chunk and set the first bit to one and so on.

Finally, we keep counting k '1's starting from the beginning of the BitVector. When k'th 1 is found, we multiply the chunk number of that 1 with 32 and add the location of this 1 in that chunk (i * 32 + bitCount).

Youness
  • 1,526
  • 19
  • 26