算法实战:快速选择解决第 K 大元素与最小 K 个数问题
在处理数组查找类问题时,全排序往往显得过于重手。今天我们来聊聊如何利用**快速选择算法(Quick Select)**高效解决两个经典场景:数组中的第 K 个最大元素,以及最小的 K 个数。
45. 数组中的第 K 个最大元素
题目描述
给定一个整数数组 nums 和一个整数 k,返回该数组中第 k 个最大的元素。
核心思路
很多人第一反应是排序后取索引,但时间复杂度是 O(NlogN)。其实我们可以利用快排的分区思想进行优化。
在标准的三路快排中,我们将数组划分为 [小于基准]、[等于基准]、[大于基准] 三个区域。对于找第 K 大的数,我们只需要关注这三个区域的长度:
- 如果**右侧区域(大于基准)**的元素个数 >= k,说明目标就在右边,递归进入右区间。
- 如果**中间区域(等于基准)**包含了目标位置,那么基准值本身就是答案。
- 否则,目标在左侧,调整 k 值后递归左区间。
这种策略下,平均时间复杂度可以逼近 O(N)。
C++ 代码实现
class Solution {
public:
int Top_k(vector<int>& nums, int left, int right, int k) {
if (left == right) {
return nums[left];
}
int l = left - 1, r = right + 1, i = left;
// 随机选择基准元素,避免最坏情况
int key = nums[rand() % (right - left + 1) + left];
// 三路划分:大于 key | 等于 key | 小于 key
while (i < r) {
if (nums[i] > key) {
swap(nums[i], nums[--r]);
} else if (nums[i] < key) {
swap(nums[i++], nums[++l]);
} {
i++;
}
}
(right - r + >= k) {
(nums, r, right, k);
}
(right - l >= k) {
key;
}
{
(nums, left, l, k - (right - l));
}
}
{
(());
(nums, , nums.() - , k);
}
};




