题目:数组中的第K个最大元素
解法一:优先队列(堆)
- 时间复杂度:O(n log k) 空间复杂度:O(k)
手动维护一个大小为 k 的最小堆(堆顶是堆中的最小元素),每当堆的大小超过 k 时,就将堆顶的元素弹出,这样最终留下来的堆顶元素就是 第k大的元素
1int findKthLargest(vector<int>& nums, int k)
2{
3 std::priority_queue<int, std::vector<int>, greater<int>> pq;
4 for(const int& num : nums)
5 {
6 pq.emplace(num);
7 if(k < pq.size())
8 pq.pop();
9 }
10 return pq.top();
11}
解法二:快速选择
平均时间复杂度是 O(n)
常规情况下的快排的平均时间复杂度是nlogn,所以需要手写一个快排
具体实现:
定义三个数组,分别存储大于、等于、小于基准值的数,通过一轮循环将其填充
之后的判断存在三种情况:
1.k 小于等于 big 数组的大小——也就是说,big数组中存在第一大、第二大…..一直到第 k 大甚至更多元素,此时第 k 大的元素一定存在于 big 数组中,那么接下来就只需要在 big 数组里寻找即可
2.k 大于原数组大小减去 small 数组大小——nums.size() - small.size() 代表的是 big 数组加上 equal 数组的大小,也就是说此时 big 与 equal 数组中的元素数量加起来都不足 k 个,那么第 k 大的元素就一定在 small数组里了;注意 quickSeclet 的第二个参数从 k 变成了 k - nums.size() + small.size(),这是因为,相对于整个数组,需要寻找的是第 k 大的元素,而相对于 small 数组来说,这个元素是第
k - (nums.size() - small.size())大的元素
3.第 k 大位于 equal里面
此时直接返回基准值即可
1int findKthLargest(vector<int>& nums, int k)
2{
3 return quickSeclet(nums, k);
4}
5
6int quickSeclet(vector<int>& nums, int k)
7{
8 std::vector<int> big, equal, small;
9 int pivot = nums[std::rand() % nums.size()];
10 for(int num : nums)
11 {
12 if(num < pivot) small.push_back(num);
13 else if(pivot < num) big.push_back(num);
14 else equal.push_back(num);
15 }
16
17 if(k <= big.size())
18 return quickSeclet(big, k);
19 if(nums.size() - small.size() < k)
20 return quickSeclet(small, k - nums.size() + small.size());
21 return pivot;
22}