2.2. QuickSelect

This can be considered an optimization of the previous approach. In this, we pick the QuickSort for sorting. Analyzing the problem statement, we realize that we don’t actually need to sort the entire array — we only need to rearrange its contents so that the kth element of the array is the kth largest or smallest.

In QuickSort, we pick a pivot element and move it to its correct position. We also partition the array around it. In QuickSelect, the idea is to stop at the point where the pivot itself is the kth largest element.

We can optimize the algorithm further if we don’t recur for both left and right sides of the pivot. We only need to recur for one of them according to the position of the pivot.

Let’s look at the basic ideas of the QuickSelect algorithm:

Pick a pivot element and partition the array accordingly

Pick the rightmost element as pivot

Reshuffle the array such that pivot element is placed at its rightful place — all elements less than the pivot would be at lower indexes, and elements greater than the pivot would be placed at higher indexes than the pivot

If pivot is placed at the kth element in the array, exit the process, as pivot is the kth largest element

If pivot position is greater than k, then continue the process with the left subarray, otherwise, recur the process with right subarray

We can write generic logic which can be used to find the kth smallest element as well. We’ll define a method findKthElementByQuickSelect() which will return the kth element in the sorted array.

If we sort the array in ascending order, the kth element of an array will be the kth smallest element. To find the kth largest element, we can pass k= length(Array) – k.

Now let’s implement the partition method, which picks the rightmost element as a pivot, puts it at the appropriate index, and partitions the array in such a way that elements at lower indexes should be less than the pivot element.

Similarly, elements at higher indexes will be greater than the pivot element:

This solution works in O(n) time on average. However, in the worst case, the time complexity will be O(n^2).

2.3. QuickSelect with Randomized Partition

This approach is a slight modification of the previous approach. If the array is almost/fully sorted and if we pick the rightmost element as a pivot, the partition of left and right subarrays will be highly uneven.

This method suggests picking the initial pivot element in a random manner. We don’t need to change the partitioning logic though.

Instead of calling partition, we call the randomPartition method, which picks a random element and swaps it with the rightmost element before finally invoking the partition method.

3. Conclusion

In this article, we discussed different solutions to find the kth largest (or smallest) element in an array of unique numbers. The simplest solution is to sort the array and return the kth element. This solution has a time complexity of O(n*logn).

We also discussed two variations of Quick Select. This algorithm isn’t straightforward but it has a time complexity of O(n) in average cases.

As always, the complete code for the algorithm can be found over on GitHub.