随机选择(Randomized Select)

用三路 partition 在期望 O(n) 时间内找第 K 小/大。

#resource / algorithm #type / concept #status / growing #algo / selection

[!info] related notes 算法面试题型 MOC 快速排序

随机选择(Randomized Select)

目标:在无序数组中找第 K 小(或第 K 大)。

思想

随机选 pivot 做一次 partition 后:

  • 如果目标下标落在 “< pivot” 区间,继续在左边找。
  • 如果落在 “> pivot” 区间,继续在右边找。
  • 如果落在 “== pivot” 区间,答案就是 pivot。

每次都能丢掉一大块不可能的元素,期望时间复杂度 $O(n)$。

实现要点

  • 用三路划分(<, ==, >)更稳,重复元素多时优势明显。
  • 第 K 大可以转换成第 (n-k) 小。

Java Template (Iterative)

import java.util.*;

public class RandomizedSelect {
    static int findKthLargest(int[] nums, int k) {
        // kth largest => index (n - k) in sorted order (0-indexed)
        return select(nums, nums.length - k);
    }

    static int select(int[] arr, int index) {
        int l = 0, r = arr.length - 1;
        while (l <= r) {
            int pivot = arr[l + (int) (Math.random() * (r - l + 1))];
            int[] range = partition(arr, l, r, pivot);
            if (index < range[0]) {
                r = range[0] - 1;
            } else if (index > range[1]) {
                l = range[1] + 1;
            } else {
                return arr[index];
            }
        }
        throw new IllegalArgumentException("index out of range");
    }

    static int[] partition(int[] arr, int l, int r, int pivot) {
        int less = l - 1;
        int more = r + 1;
        int i = l;
        while (i < more) {
            if (arr[i] < pivot) swap(arr, ++less, i++);
            else if (arr[i] > pivot) swap(arr, i, --more);
            else i++;
        }
        return new int[] { less + 1, more - 1 };
    }

    static void swap(int[] arr, int i, int j) {
        int t = arr[i];
        arr[i] = arr[j];
        arr[j] = t;
    }
}
创建于 2026/3/16 更新于 2026/5/27