在处理'第 K 大'或'最小 K 个数'这类问题时,全排序往往效率不高。这里介绍一种基于快速排序思想优化的快速选择算法(Quick Select),平均时间复杂度可降至 O(N)。
45. 数组中的第 K 个最大元素
题目描述
给定整数数组 nums 和整数 k,请返回该数组中第 k 个最大的元素。
注意你需要找的是排序后第 k 大的元素,而不是第 k 个不同的元素。
解法思路
核心在于利用快速排序的分区(Partition)逻辑。在快排中,我们将数组分为三块:大于基准值、等于基准值、小于基准值。通过计算每个区间的长度,我们可以直接判断目标元素落在哪个区间,从而避免对另一侧进行递归处理。
对于第 K 大元素,我们关注的是右侧(较大值)区域的元素数量。如果右侧区域元素个数 >= k,说明目标在右边;如果在中间区域,则当前基准值即为答案;否则在左边,且需要调整 k 的值。
代码实现
class Solution {
public:
int Top_k(vector<int>& nums, int left, int right, int k) {
if (left == right) {
return nums[left];
}
// 三路划分:[left, l] [l+1, r-1] [r, right]
int l = left - 1, r = right + 1, i = left;
// 随机选择基准元素,避免最坏情况
int key = nums[rand() % (right - left + 1) + left];
while (i < r) {
if (nums[i] > key) {
swap(nums[i], nums[--r]);
} else if (nums[i] < key) {
swap(nums[i++], nums[++l]);
} else {
i++;
}
}
// 若右边区域元素个数>=k,说明第 k 大的数在右边区域
if (right - r + 1 >= k) {
return Top_k(nums, r, right, k);
}
(right - l >= k) {
key;
}
{
(nums, left, l, k - (right - l));
}
}
{
(());
(nums, , nums.() - , k);
}
};


