数组中的第K个最大元素
你这段代码实现的是一个经典的算法:快速选择(QuickSelect)算法,用于在未排序的数组中查找第 k 大的元素。整体思路和快速排序类似,但只处理一部分数组,从而提高效率。下面我会给出详细思路、每一步运行过程和举例说明。
class Solution {
public:
int findKthLargest(vector<int>& nums, int k) {
return quickSelect(nums, k);
}
int quickSelect(vector<int>& nums, int k) {
// 基于快排的快速选择
// 随机选择基准数字
int p = nums[rand() % nums.size()];
// 将大于等于小于的元素分别放入三个数组
vector<int> big, equal, small;
for (int a : nums) {
if (a < p) small.push_back(a);
else if (a == p) equal.push_back(a);
else big.push_back(a);
}
// 第k大元素在big中, 递归划分
if (k <= big.size()) {
return quickSelect(big, k);
}
// 第k大元素在small中, 递归划分
if (big.size() + equal.size() < k) {
return quickSelect(small, k - (big.size() + equal.size()));
}
// 第k大元素在equal中, 返回p
return p;
}
};
✅ 一、问题定义
给定一个整数数组 nums 和一个整数 k,你要找出数组中第 k 大的元素。
注意: 第 k 大,意味着比它大的元素有 (k - 1) 个。
✅ 二、算法核心思想(QuickSelect)
快速选择基于快速排序中的“分区”思想:
1. 每次随机选择一个基准数 pivot
2. 把原数组划分成三部分:
• big: 所有比 pivot 大的
• equal: 所有等于 pivot 的
• small: 所有比 pivot 小的
3. 判断第 k 大在哪一组中:
• 如果 k <= big.size():说明第 k 大在 big 里 → 递归查找
• 如果 k > big.size() + equal.size():说明第 k 大在 small 里 → 递归查找,并更新 k
• 否则,第 k 大就在 equal 中,直接返回 pivot
✅ 三、代码详解
🔹 函数接口:
int findKthLargest(vector<int>& nums, int k)
• 主函数,调用快速选择来找第 k 大元素。
🔹 快速选择函数:
int quickSelect(vector<int>& nums, int k)
1. 随机选一个基准数
int p = nums[rand() % nums.size()];
• 用随机下标选一个 pivot,防止最坏时间复杂度。
2. 三分法分区
vector<int> big, equal, small;
for (int a : nums) {
if (a < p) small.push_back(a);
else if (a == p) equal.push_back(a);
else big.push_back(a);
}
• 按照 pivot 分为三部分:
• big:大于 pivot 的数
• equal:等于 pivot 的数
• small:小于 pivot 的数
3. 判断第 k 大在哪一部分
if (k <= big.size()) {
return quickSelect(big, k);
}
if (big.size() + equal.size() < k) {
return quickSelect(small, k - (big.size() + equal.size()));
}
return p;
🧪 四、举个例子
输入:
nums = [3, 2, 1, 5, 6, 4], k = 2
目的是找 第 2 大元素。
第一次递归:
• 假设随机选到 pivot = 4
• 划分结果:
• big = [5, 6]
• equal = [4]
• small = [3, 2, 1]
• 因为 k = 2 且 big.size() = 2,所以第 2 大在 big 中
• → 递归查找 quickSelect([5,6], 2)
第二次递归:
• 假设 pivot = 5
• 划分结果:
• big = [6]
• equal = [5]
• small = []
• big.size() = 1,equal.size() = 1,所以:
• k = 2,在 big + equal 范围内
• → 返回 pivot = 5
最终结果为 5,即第 2 大的数。
当然可以,我们用一个新的数据来手动运行你的这段代码,演示一下每一步的执行过程。
✅ 新示例输入:
nums = [7, 10, 4, 3, 20, 15]
k = 3
我们要找的是第 3 大元素。
🔄 第一次调用:quickSelect([7, 10, 4, 3, 20, 15], 3)
假设随机选的 pivot = 10
我们开始分组:
• big: [20, 15](比 10 大的)
• equal: [10]
• small: [7, 4, 3](比 10 小的)
看 k = 3 落在哪一段:
• big.size() = 2
• equal.size() = 1
• big + equal = 3,刚好第 3 大就在前两部分!
因为 k <= big.size() + equal.size() 且 k > big.size(),说明第 3 大在 equal 中。
✅ 返回:pivot = 10
🎉 最终结果:
第 3 大元素 = 10
✅ 每一步小结
步骤 | 内容 |
---|---|
原数组 | [7, 10, 4, 3, 20, 15] |
pivot | 10 |
分组 | big = [20, 15], equal = [10], small = [7, 4, 3] |
目标位置 | 第 3 大,正好在 equal 中 |
结果 | 返回 10 |