#
Quick Select (122B)
Question. Given an unsorted
A[1...N]: List<number>and a positive integerk,1 <= k <= N, how do we find the k-th smallest element of A in O(n) time?
For example, A = [3,2,1,5,6,4], k = 2 gives us 2.
#
One Armed Quick Select
The idea is similar to quick sort. Partition A by some pivot, then recursively search the left and right half with respect to the pivot.
- Let the pivot value be
p, pivot index bepivot_index. Recall thatA[i]<pifi < pivot_index, andA[i] >= pifi >= pivot_index
function quickSelect(A: [1...N], k: int) -> int:
pivot_value = selectPivot(A) // black box subroutine
small, large = [], []
for a in A:
if a < pivot_value:
small.push(a)
else if a > pivot_value:
large.push(a)
s = len(small)
l = len(large)
if k < s:
return quickSelect(small, k)
else if k > N - s:
return quickSelect(large, k - (N - s))
else:
return pivot_value
#
Example Walkthrough
For A = [3,2,1,5,6,4], k = 2, we have:
N = 6
pivot_value = 4
small = [3, 2, 1]
large = [5, 6]
2 < len(small), call quickSelect(small, 2)
---
N = 3
pivot_value = 1
small = []
large = [3, 2]
Neither 2 < 0 nor 2 > 3 - 0, so we hit the else case
return 1
#
Decide which half to search
If p is the pivot value, then after partition(), the array A looks like this:
\tt \underbrace{\overbrace{...}^{\text{values < p}}}_{\text{left half}},\;p\dots p,\;\underbrace{\overbrace{...}^{\text{values > p}}}_{\text{right half}}Notice that there's a chunk of p next to each other in the middle. Recall that the idea is to recursively search the left and right half. If k < len(left), then the kth smallest is in left, so we just do the recursive call on left.
If is in the right half,