🧠
Quickselect (Partition-based Selection)
💡 Quickselect is an efficient selection algorithm related to quicksort that finds the kth largest element without sorting the entire array.
Intuition
Partition the array around a pivot so that elements greater than pivot are on one side. Recursively search the side that contains the kth largest element until found.
Algorithm
- Choose a pivot element randomly or from the array.
- Partition the array so elements greater than pivot are on the left, smaller on the right.
- Check the pivot's position; if it matches kth largest index, return it.
- Otherwise, recurse on the side that contains the kth largest element.
💡 This algorithm is tricky because it uses partitioning logic and recursion, but it avoids sorting the entire array.
import random
def partition(nums, left, right):
pivot = nums[right]
i = left
for j in range(left, right):
if nums[j] > pivot:
nums[i], nums[j] = nums[j], nums[i]
i += 1
nums[i], nums[right] = nums[right], nums[i]
return i
def quickselect(nums, left, right, k):
if left == right:
return nums[left]
pivot_index = partition(nums, left, right)
if pivot_index == k:
return nums[pivot_index]
elif pivot_index < k:
return quickselect(nums, pivot_index + 1, right, k)
else:
return quickselect(nums, left, pivot_index - 1, k)
def findKthLargest(nums, k):
return quickselect(nums, 0, len(nums) - 1, k - 1)
# Driver code
if __name__ == '__main__':
print(findKthLargest([3,2,1,5,6,4], 2)) # Output: 5
Line Notes
import randomImports random module if pivot randomization is added (currently unused)
def partition(nums, left, right):Partitions array around pivot for quickselect
pivot = nums[right]Selects the last element as pivot for partitioning
if nums[j] > pivot:Ensures elements greater than pivot go to left side
nums[i], nums[j] = nums[j], nums[i]Swaps elements to maintain partition invariant
if pivot_index == k:Checks if pivot is at kth largest position to return result
import java.util.*;
public class Solution {
public static int partition(int[] nums, int left, int right) {
int pivot = nums[right];
int i = left;
for (int j = left; j < right; j++) {
if (nums[j] > pivot) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
i++;
}
}
int temp = nums[i];
nums[i] = nums[right];
nums[right] = temp;
return i;
}
public static int quickselect(int[] nums, int left, int right, int k) {
if (left == right) return nums[left];
int pivotIndex = partition(nums, left, right);
if (pivotIndex == k) return nums[pivotIndex];
else if (pivotIndex < k) return quickselect(nums, pivotIndex + 1, right, k);
else return quickselect(nums, left, pivotIndex - 1, k);
}
public static int findKthLargest(int[] nums, int k) {
return quickselect(nums, 0, nums.length - 1, k - 1);
}
public static void main(String[] args) {
int[] nums = {3,2,1,5,6,4};
System.out.println(findKthLargest(nums, 2)); // Output: 5
}
}
Line Notes
import java.util.*;Imports utility classes
int pivot = nums[right];Chooses pivot as last element for partitioning
if (nums[j] > pivot)Partitions elements greater than pivot to left
int temp = nums[i]; nums[i] = nums[j]; nums[j] = temp;Swaps elements to maintain partition
if (pivotIndex == k)Checks if pivot is kth largest element
#include <iostream>
#include <vector>
using namespace std;
int partition(vector<int>& nums, int left, int right) {
int pivot = nums[right];
int i = left;
for (int j = left; j < right; j++) {
if (nums[j] > pivot) {
swap(nums[i], nums[j]);
i++;
}
}
swap(nums[i], nums[right]);
return i;
}
int quickselect(vector<int>& nums, int left, int right, int k) {
if (left == right) return nums[left];
int pivotIndex = partition(nums, left, right);
if (pivotIndex == k) return nums[pivotIndex];
else if (pivotIndex < k) return quickselect(nums, pivotIndex + 1, right, k);
else return quickselect(nums, left, pivotIndex - 1, k);
}
int findKthLargest(vector<int>& nums, int k) {
return quickselect(nums, 0, nums.size() - 1, k - 1);
}
int main() {
vector<int> nums = {3,2,1,5,6,4};
cout << findKthLargest(nums, 2) << endl; // Output: 5
return 0;
}
Line Notes
#include <vector>Includes vector container
int pivot = nums[right];Selects pivot element for partitioning
if (nums[j] > pivot)Partitions elements greater than pivot to left
swap(nums[i], nums[j]);Swaps elements to maintain partition invariant
if (pivotIndex == k)Checks if pivot is at kth largest position
function partition(nums, left, right) {
let pivot = nums[right];
let i = left;
for (let j = left; j < right; j++) {
if (nums[j] > pivot) {
[nums[i], nums[j]] = [nums[j], nums[i]];
i++;
}
}
[nums[i], nums[right]] = [nums[right], nums[i]];
return i;
}
function quickselect(nums, left, right, k) {
if (left === right) return nums[left];
let pivotIndex = partition(nums, left, right);
if (pivotIndex === k) return nums[pivotIndex];
else if (pivotIndex < k) return quickselect(nums, pivotIndex + 1, right, k);
else return quickselect(nums, left, pivotIndex - 1, k);
}
function findKthLargest(nums, k) {
return quickselect(nums, 0, nums.length - 1, k - 1);
}
// Test
console.log(findKthLargest([3,2,1,5,6,4], 2)); // Output: 5
Line Notes
function partition(nums, left, right)Partitions array around pivot for quickselect
let pivot = nums[right];Selects pivot element for partitioning
if (nums[j] > pivot)Partitions elements greater than pivot to left
[nums[i], nums[j]] = [nums[j], nums[i]];Swaps elements to maintain partition
if (pivotIndex === k)Checks if pivot is kth largest element
TimeAverage O(n), Worst O(n^2)
SpaceO(1) additional space
Partitioning reduces problem size each recursion; average case is linear but worst case is quadratic.
💡 For n=100,000, average case is about 100,000 operations, but worst case can degrade if pivot choices are poor.
Interview Verdict: Accepted and optimal average case
Quickselect is the fastest average solution but requires careful implementation and understanding of partitioning.