Skip to content
ΣDSA Patterns
Menu
Language

Quick Select

Guide 6 of 6 · Path 6 of 6

Interactive

Mental model

A worked animation for this problem. Scrub steps or press space to pause; re-tell the invariant out loud.

Step 1 of 6
3
6
7
10

target index n−k = 0

Kth largest as a numeric string. ["3","6","7","10"], k=4 → the smallest, "3".

Demo preview: These solutions pass the automated test suite but have not been human-reviewed. Treat trade-offs and prose as draft.

Find the Kth Largest Integer in the Array

Problem (restated)

An array of integers given as strings (no leading zeros except "0", values up to 100 digits). Return the kth largest as a string.

Intuition

Same partition as LC 215, with a numeric string order: longer is larger; equal length → lexicographic. You cannot parse as a 64-bit int. Target index is still n-k.

Approaches

Quick select on numeric strings

Unverified
Time O(n · L) averageSpace O(1)

Idea. cmp(a, b): compare lengths, then the strings. Randomized partition until the pivot sits at n-k. Return that string (do not convert).

Walkthrough. ["3","6","7","10"], k=4 → smallest → "3". ["2","21","12","1"], k=3 → "2".

Trade-offs. Average O(n) comparisons, each O(L). Sorting is O(n log n · L) and simpler if n is small. Randomize the pivot. Mutates the input.

Solution
export function kthLargestNumber(nums: string[], k: number): string {
  const target = nums.length - k;
  let lo = 0, hi = nums.length - 1;
  while (lo <= hi) {
    const p = partition(nums, lo, hi);
    if (p === target) return nums[p]!;
    if (p < target) lo = p + 1;
    else hi = p - 1;
  }
  return nums[lo]!;
}

function cmp(a: string, b: string): number {
  if (a.length !== b.length) return a.length - b.length;
  return a < b ? -1 : a > b ? 1 : 0;
}

function partition(nums: string[], lo: number, hi: number): number {
  const rand = lo + Math.floor(Math.random() * (hi - lo + 1));
  [nums[rand], nums[hi]] = [nums[hi]!, nums[rand]!];
  const pivot = nums[hi]!;
  let i = lo;
  for (let j = lo; j < hi; j++) {
    if (cmp(nums[j]!, pivot) < 0) {
      [nums[i], nums[j]] = [nums[j]!, nums[i]!];
      i++;
    }
  }
  [nums[i], nums[hi]] = [nums[hi]!, nums[i]!];
  return i;
}
export function kthLargestNumber(nums: string[], k: number): string {
  const target = nums.length - k;
  let lo = 0, hi = nums.length - 1;
  while (lo <= hi) {
    const p = partition(nums, lo, hi);
    if (p === target) return nums[p]!;
    if (p < target) lo = p + 1;
    else hi = p - 1;
  }
  return nums[lo]!;
}

function cmp(a: string, b: string): number {
  if (a.length !== b.length) return a.length - b.length;
  return a < b ? -1 : a > b ? 1 : 0;
}

function partition(nums: string[], lo: number, hi: number): number {
  const rand = lo + Math.floor(Math.random() * (hi - lo + 1));
  [nums[rand], nums[hi]] = [nums[hi]!, nums[rand]!];
  const pivot = nums[hi]!;
  let i = lo;
  for (let j = lo; j < hi; j++) {
    if (cmp(nums[j]!, pivot) < 0) {
      [nums[i], nums[j]] = [nums[j]!, nums[i]!];
      i++;
    }
  }
  [nums[i], nums[hi]] = [nums[hi]!, nums[i]!];
  return i;
}

Template connection

Quick Select with a custom order. LC 215 is the integer version of the same loop.

Reflection