- 数组中的第K个最大元素
在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。
示例 1:
输入: [3,2,1,5,6,4] 和 k = 2
输出: 5
示例 2:
输入: [3,2,3,1,2,4,5,5,6] 和 k = 4
输出: 4
说明:
你可以假设 k 总是有效的,且 1 ≤ k ≤ 数组的长度。
方法一
采用快速排序的思想,随机选取一个值作为分割线,分割线左边的都不比这个值大,分割线右边都比这个值大。
只需要比较分割线的索引值与n-k的值(目标值):
如果目标点正好等于分割点,说明此时的分割点正是要找的第K大的值;
如果目标点在分割点右侧,说明左侧区间有待缩减掉,仅对右半边递归;
如果目标点在分割点左侧,说明右侧区间有待缩减掉,仅对左半边递归。
class Solution {
public:
int findKthLargest(vector<int>& nums, int k) {
return findKthLargest(nums, 0, nums.size()-1, k);
}
private:
int findKthLargest(vector<int>& nums, int low, int high, int k){
int n=nums.size();
int index = partition(nums, low, high);
if(index==n-k) return nums[index];
else if(index < n-k) return findKthLargest(nums,index+1,high,k);
else return findKthLargest(nums,low,index-1,k);
}
int partition(vector<int>& nums, int low, int high) {
uniform_int_distribution<int> u(low, high);
default_random_engine e;//生成无符号随机整数
std::swap(nums[u(e)], nums[high]);//避免最糟糕的情况出现,随机选值放到最右端
int i = 0, j = 0;
for (i = low, j = low;j < high;++j) {//从头到尾遍历每个数,但不遍历最后的基准值
if (nums[j] <= nums[high]) {//如果发现当前数不大于基准值
std::swap(nums[i++], nums[j]);//把这个不大于基准值的数与i位置上的数交换,同时i++
}
}//结束后,i之前的所有的数都不大于基准值,i之后所有的数都大于基准值;退出的时候j=high
std::swap(nums[i], nums[j]);//把j位置的数(基准值)换到i位置上来
return i;
}
};
后续方法参考:https://blog.csdn.net/lv1224/article/details/80112229
方法二(用STL的轮子nth_element())
使用STL库函数 nth_element()
,通过调用nth_element(start, start+n, end)
方法可以使第n大元素处于第n位置(从0开始,其位置是下标为 n的元素),并且比这个元素小的元素都排在这个元素之前,比这个元素大的元素都排在这个元素之后,但不能保证他们是有序的
class Solution {
public:
int findKthLargest(vector<int>& nums, int k) {
nth_element(nums.begin(),nums.end()-k,nums.end());
return *(nums.end()-k);
}
};
方法三(用STL的轮子sort)
直接排序,取值
class Solution {
public:
int findKthLargest(vector<int>& nums, int k) {
sort(nums.begin(),nums.end());
return nums[nums.size()-k];
}
};
方法四
利用 multiset 本身有序,维持 multiset 大小 K,则 multiset 首元素即为所求。
注意: 由于数组本身存在重复元素,所以这里要用multiset。
class Solution {
public:
int findKthLargest(vector<int>& nums, int k) {
multiset<int> s;
for(auto &m:nums){
s.insert(m);
if(s.size()>k) s.erase(s.begin());
}
return *s.begin();
}
};