45. 数组中的第 k 个最大元素
题目描述
给定整数数组 nums 和整数 k,请返回该数组中第 k 个最大的元素。
注意这里需要的是排序后第 k 大的元素,而不是第 k 个不同的元素。例如输入 [3,2,1,5,6,4],k=2,输出应为 5。
解法思路:快速选择算法
这道题最直观的做法是排序,时间复杂度为 O(NlogN)。但如果数据量很大,我们其实不需要完全有序,只需要找到第 k 个位置即可。这时候**快速选择算法(Quick Select)**就派上用场了。
它的核心思想来源于快速排序的分区操作(Partition)。在快排中,我们将数组划分为小于基准、等于基准、大于基准三部分。利用这个特性,我们可以判断目标元素究竟落在哪个区间:
- 计算区间长度:统计当前分区后,右侧区域(大于基准)和中间区域(等于基准)的元素个数。
- 定位目标:
- 如果右侧区域元素个数 >= k,说明第 k 大就在右边,递归处理右半部分。
- 如果右侧 + 中间区域个数 >= k,说明基准值就是我们要找的第 k 大元素。
- 否则,目标在左侧,需要在左边继续查找,同时更新 k 的值(减去已排除的元素数量)。
这种三路划分(Dutch National Flag 问题变种)能有效处理大量重复元素的情况,避免退化。
C++ 参考实现
class Solution {
public:
// 快速选择主函数,寻找第 k 大的数
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];
// 三路划分:[left, l] < key, [l+1, r-1] == key, [r, right] > key
while (i < r) {
if (nums[i] > key) {
swap(nums[i], nums[--r]);
} else (nums[i] < key) {
(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);
}
};


