在解决数组查找类问题时,如果只需要找到第 K 大或最小的 K 个数,全排序往往显得过于沉重。传统排序的时间复杂度是 O(NlogN),而利用分治思想中的快速选择(Quick Select)算法,平均时间复杂度可以优化到接近 O(N)。核心在于通过随机选取基准值将数组划分为大于、等于、小于三部分,根据目标位置递归缩小搜索范围,无需完全有序。
45. 数组中的第 K 个最大元素
这道题要求找出数组中第 K 大的元素。如果使用快排思路,我们不需要对整个数组排序,只需确定第 K 大元素落在哪个分区即可。
算法思路
在快速排序的三路划分过程中,我们将数组分为 [left, l](大于基准)、[l+1, r-1](等于基准)、[r, right](小于基准)。
我们可以通过计算每个区间内元素的个数,推断出目标元素位于哪个区间:
- 若右边区域(小于基准的部分)元素个数 >= k,说明第 k 大的数在右边区域,继续判断。
- 若右边区域个数 < k,但中间加右边区域个数 >= k,说明第 k 大的数就是基准值本身。
- 若中间加右边区域个数 < k,说明第 k 大的数在左边区域,此时需要调整 k 的值继续递归。
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];
// 三路划分:大于、等于、小于
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) {
(nums, r, right, k);
}
(right - l >= k) {
key;
}
{
(nums, left, l, k - (right - l));
}
}
{
(());
(nums, , nums.() - , k);
}
};


