问题描述:
Find the kth largest element in an unsorted array. Note that it is the kth largest element in the sorted order, not the kth distinct element.
For example,
Given [3,2,1,5,6,4] and k = 2, return 5.
Note:
You may assume k is always valid, 1 ≤ k ≤ array’s length.
问题求解:
方法一:利用快排的思想,使用快速选择算法(QuickSelect),时间复杂度为O(N).
class Solution {
public:
int findKthLargest(vector<int>& nums, int k) {
int n=nums.size();
vector<int> left;
vector<int> right;
int key=nums[0];//(1)将nums[0]设置为主元,以此划分左右两部分
for(int i=1;i<n;i++)
{
if(nums[i] > key)
{//(2)大于key的放右边
right.push_back(nums[i]);
}
else if(nums[i] < key)
{//(3)小于key的放左边
left.push_back(nums[i]);
}
}
int nr=right.size();
int nl=left.size();
if(k <= nr)
{//(4)k<=nr则直接在右边找
return findKthLargest(right, k);
}
if(k > n-nl)
{//(5)k>n-nl则需在左边找k-(n-nl)个
return findKthLargest(left, k-(n-nl));
}
return key;//(6)主元即是第k大
}
};
进一步,优化空间复杂度到O(1),代码如下:
class Solution {
public:
int findKthLargest(vector<int>& nums, int k) {
int L = 0, R = nums.size() - 1;
while (L < R) {
int left = L, right = R;
int key = nums[left];//(1)主元
while (left < right) {
//(2)将大于key的放左边
while (left < right && nums[right] < key) --right;
nums[left] = nums[right];
//(3)将小于key的放右边
while (left < right && nums[left] >= key) ++left;
nums[right] = nums[left];
}
nums[left] = key;
if (left == k - 1) return nums[k - 1];
else if (left > k - 1) R = left - 1;//(4)更新R
else L = left + 1;//(5)更新L
}
return nums[k - 1];
}
};
方法二:先排序再选择。时间复杂度:O(N*logN),空间复杂度:O(1)。
class Solution {
public:
int findKthLargest(vector<int>& nums, int k) {
sort(nums.begin(), nums.end());//(1)排序
return nums[nums.size() - k];//(2)找到第k大元素
}
};
方法三:建立大顶堆。make_heap()默认生成的是大顶堆,该函数接受两个随机迭代器,分别表示first,end,区间范围。也可通过自定义的cmp来生成小顶堆。
pop_heap() 首元素和末元素交换,再重新堆排序。
pop_back() 删除容器中最后一个元素。
代码:
class Solution {
public:
int findKthLargest(vector<int>& nums, int k) {
make_heap(nums.begin(), nums.end());//(1)生成大顶堆
for(int i=0; i<k-1;i++)
{//弹出k-1个
//(2)把堆顶元素取出来,放到数组或者是vector的末尾,用原来末尾元素去替代
//然后end迭代器减1,执行siftdown()下溯函数来重新调整堆序。
//执行完毕后,最大的元素并没有被取走,而是放于底层容器的末尾。
pop_heap(nums.begin(), nums.end());
//(3)若要取走,可使用pop_back()函数。
nums.pop_back();
}
return nums.front();//(4)得到第k个大的
}
};