mobile wallpaper 1mobile wallpaper 2mobile wallpaper 3mobile wallpaper 4mobile wallpaper 5mobile wallpaper 6
510 字
3 分钟
【算法笔记】(七)随机选择算法
2026-01-15
统计加载中...

随机选择算法(Randomized Select / Quickselect)#

题目描述#

在无序数组中寻找第 K 大的数。

给定整数数组 nums 和整数 k,请返回数组中第 k 大的元素。
请注意:你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。

要求#

  • 时间复杂度:O(n)(期望)
  • 额外空间复杂度:O(1)

思路说明#

K 大等价于:把数组按从小到大排序后,找到下标为 n - K 的元素(0-based)。

例如:

  • 数组长度为 n
  • K 大元素 = 排序后位置 n - K 的元素

因此可以将问题转换为:在数组中寻找“第 (n - K) 小(按下标)”的元素,用随机选择(Quickselect)实现,期望 O(n)

Java 实现代码#

package org.example;
public class Main {
static int[] arr = {0, 1, 2, 3, 4, 5, 6, 7};
public static void main(String[] args) {
int K = 5;
// 将问题转换:求第K大的数 = 求排序后下标为 arr.length - K 的数
int i = randomizedSelect(arr.length - K);
System.out.println(i);
}
// 如果 arr 排序后,第 k 位置(0-based)的数是什么
public static int randomizedSelect(int k) {
int ans = 0;
for (int l = 0, r = arr.length - 1; l <= r; ) {
// 在 [l, r] 随机选一个 pivot 值 x
int x = arr[l + (int) (Math.random() * (r - l + 1))];
// 三路划分:<x | ==x | >x
partition(l, r, x);
// 根据 x 所在区间与 k 的关系,缩小搜索范围
if (first > k) r = first - 1;
else if (last < k) l = last + 1;
else {
ans = x;
break;
}
}
return ans;
}
static int first;
static int last;
// 已知数组在 [l, r] 范围内一定有值 x
// 划分数组:<x 的放左边,==x 的放中间,>x 的放右边
// 更新全局变量 first、last 为 ==x 的左右边界
private static void partition(int l, int r, int x) {
first = l;
last = r;
int i = l;
while (i <= last) {
if (arr[i] == x) i++;
else if (arr[i] < x) swap(first++, i++);
else swap(i, last--);
}
}
private static void swap(int a, int b) {
int temp = arr[a];
arr[a] = arr[b];
arr[b] = temp;
}
}
【算法笔记】(七)随机选择算法
http://hgqwd.icu/posts/suanfa7/
作者
天线宝宝死于谋杀
发布于
2026-01-15
许可协议
CC BY-NC-SA 4.0

部分信息可能已经过时

封面
Sample Song
Sample Artist
封面
Sample Song
Sample Artist
0:00 / 0:00