Kth Smallest Element in Unsorted Array

(referrence: GeeksforGeeks, Kth Largest Element in Array)

This is a common algorithm problem appearing in interviews.

There are four basic solutions.

Solution 1 -- Sort First

A Simple Solution is to sort the given array using a O(n log n) sorting algorithm like Merge Sort,Heap Sort, etc and return the element at index k-1 in the sorted array. Time Complexity of this solution is O(n log n).

Java Arrays.sort()

1 public class Solution{
2     public int findKthSmallest(int[] nums, int k) {
3         Arrays.sort(nums);
4         return nums[k];
5     }
6 }

Solution 2 -- Construct Min Heap

A simple optomization is to create a Min Heap of the given n elements and call extractMin() k times.

To build a heap, time complexity is O(n). So total time complexity is O(n + k log n).

Java Priority Queue

Using PriorityQueue(Collection<? extends E> c), we can construct a heap from array or other object in linear time.

By defaule, it will create a min-heap.

Example

1 public int generateHeap(int[] nums) {
2         int length = nums.length;
3         Integer[] newArray = new Integer[length];
4         for (int i = 0; i < length; i++)
5             newArray[i] = (Integer)nums[i];
6         PriorityQueue<Integer> pq = new PriorityQueue<Integer>(Arrays.asList(newArray));
7     }

Comparator example

Comparator cmp = Colletions.reverseOrder();

 

Solution 3 -- Use Max Heap

1. Build a max-heap of size k. Put nums[0] to nums[k - 1] to heap.

2. For each element after nums[k - 1], compare it with root of heap.

  a. If current >= root, move on.

  b. If current <  root, remove root, put current into heap.

3. Return root.

Time complexity is O((n - k) log k).

(Java: PriorityQueue)

(codes)

 1 public class Solution {
 2     public int findKthSmallest(int[] nums, int k) {
 3         // Construct a max heap of size k
 4         int length = nums.length;
 5         PriorityQueue<Integer> pq = new PriorityQueue<Integer>(k, Collections.reverseOrder());
 6         for (int i = 0; i < k; i++)
 7             pq.add(nums[i]);
 8         for (int i = k; i < length; i++) {
 9             int current = nums[i];
10             int root = pq.peek();
11             if (current < root) {
12                 // Remove head
13                 pq.poll();
14                 // Add new node
15                 pq.add(current);
16             }
17         }
18         return pq.peek();
19     }
20 }

Solution 4 -- Quick Select

public class Solution {
    private void swap(int[] nums, int index1, int index2) {
        int tmp = nums[index1];
        nums[index1] = nums[index2];
        nums[index2] = tmp;
    }

    // Pick last element as pivot
    // Place all smaller elements before pivot
    // Place all bigger elements after pivot
    private int partition(int[] nums, int start, int end) {
        int pivot = nums[end];
        int currentSmaller = start - 1;
        for (int i = start; i < end; i++) {
            // If current element <= pivot, put it to right position
            if (nums[i] <= pivot) {
                currentSmaller++;
                swap(nums, i, currentSmaller);
            }
        }
        // Put pivot to right position
        currentSmaller++;
        swap(nums, end, currentSmaller);
        return currentSmaller;
    }

    public int quickSelect(int[] nums, int start, int end, int k) {
        int pos = partition(nums, start, end)
        if (pos == k - 1)
            return nums[pos];
        if (pos < k - 1)
            return quickSelect(nums, pos + 1, end, k - (pos - start + 1));
        else
            return quickSelect(nums, start, pos - 1, k);
    }
}

The worst case time complexity of this method is O(n2), but it works in O(n) on average.

 

posted @ 2015-10-10 00:14  树獭君  阅读(740)  评论(0编辑  收藏  举报