题目链接:leetcode215
题面
题目大意
求数组中第k大的数,注意区分第k大和第k小。
解题思路
暴力
每次选取一个当前最大值,重复 K 次即可找到答案
时间复杂度 O ( n k ) O(nk) O(nk),空间复杂度 O ( 1 ) O(1) O(1) 。
大根堆
维护一个大根堆,取前 K 个堆顶元素即可找到答案。
时间复杂度 O ( n + l o g 2 n k ) O(n+log_2n^k) O(n+log2nk),空间复杂度 O ( n ) O(n) O(n)。
分治
实际上就是利用快速排序的思想,每次去确定一个数的位置,然后分治两端,但是这边只需治理包含 k 的元素的那半边即可。
这部分的逻辑可以用STL的 nth_element 解决,具体讲解见 传送门
时间复杂度 O ( n ) O(n) O(n) ,空间复杂度 O ( l o g 2 n ) O(log_2n) O(log2n)。
注意:代码中我还加了三路划分优化。
代码实现
class Solution {
public:
int findKthLargest(vector<int>& nums, int k) {
return getTopKSmall(nums, 0, nums.size()-1, nums.size()-k);
}
int getTopKSmall(vector<int>& nums, int l, int r, int k) {
if (l > r) return -1;
int pat = nums[rand()%(r-l+1)+l];
int lp = l, rp = r, i = l;
while (i <= rp) {
if (nums[i] == pat) i++;
else if (nums[i] < pat) swap(nums[i++], nums[lp++]);
else swap(nums[i], nums[rp--]);
}
if (l + k < lp) return getTopKSmall(nums, l, lp-1, k);
if (l + k > rp) return getTopKSmall(nums, rp+1, r, k-rp+l-1);
return nums[k + l];
}
};