1,题目要求
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.
Example 1:
- Input: [3,2,1,5,6,4] and k = 2
- Output: 5
Example 2:
- Input: [3,2,3,1,2,4,5,5,6] and k = 4
- Output: 4
Note:
You may assume k is always valid, 1 ≤ k ≤ array’s length.
找到未排序数组中的第k个最大元素。 请注意,它是排序顺序中的第k个最大元素,而不是第k个不同元素。
2,题目思路
对于这道题,要求的是求数组的第K大的元素,但是不是第K大的不同元素。
简单实现上,我们对数组按照逆序排序,直接取第K个元素就是最后结果。
sort(nums.rbegin(), nums.rend());
return nums[k-1];
具体实现见第三部分,我们会根据Discussion中的回答,进行详细分析。
3,代码实现
STL
正如我们第二部分所说,我们可以使用STL内的部分排序算法,其中有两个合适的算法:
nth_element
partial_sort
1,nth_element
class Solution {
public:
int findKthLargest(vector<int>& nums, int k) {
nth_element(nums.begin(), nums.begin() + k - 1, nums.end(), greater<int>());
return nums[k - 1];
}
};
2,partial_sort
class Solution {
public:
int findKthLargest(vector<int>& nums, int k) {
partial_sort(nums.begin(), nums.begin() + k, nums.end(), greater<int>());
return nums[k - 1];
}
};
需要注意的是,这两个函数的参数的不同:一个是k-1,一个是k。
- 堆
同时,我们还可以通过堆来解决这个问题。
大顶堆和小顶堆都可以实现。
1,利用priority_queue
实现小顶堆
class Solution {
public:
int findKthLargest(vector<int>& nums, int k) {
priority_queue<int, vector<int>, greater<int>> pq;
for (int num : nums) {
pq.push(num);
if (pq.size() > k) {
pq.pop();
}
}
return pq.top();
}
};
2,利用priority_queue
实现大顶堆
class Solution {
public:
int findKthLargest(vector<int>& nums, int k) {
priority_queue<int> pq(nums.begin(), nums.end());
for (int i = 0; i < k - 1; i++) {
pq.pop();
}
return pq.top();
}
};
3,利用multiset
实现小顶堆
class Solution {
public:
int findKthLargest(vector<int>& nums, int k) {
multiset<int> mset;
for (int num : nums) {
mset.insert(num);
if (mset.size() > k) {
mset.erase(mset.begin());
}
}
return *mset.begin();
}
};
4,利用multiset
实现大顶堆
class Solution {
public:
int findKthLargest(vector<int>& nums, int k) {
multiset<int, greater<int>> mset(nums.begin(), nums.end());
for (int i = 0; i < k - 1; i++) {
mset.erase(mset.begin());
}
return *mset.begin();
}
};
- partition策略
还有一种比较常见的办法,则是利用快速排序中的partition思想,即每一轮排序会确定一个数字在数组中的相对位置,保证在它之前的数字都比它小,在它之后的数字都比它大。
如果我们定义一个partition函数,按照逆序的策略进行排序,并找到对应k位置,则返回该位置数字就是我们所要求的。
class Solution {
public:
int findKthLargest(vector<int>& nums, int k) {
int left = 0, right = nums.size() - 1, kth;
while (true) {
int idx = partition(nums, left, right);
if (idx == k - 1) {
kth = nums[idx];
break;
}
if (idx < k - 1) {
left = idx + 1;
} else {
right = idx - 1;
}
}
return kth;
}
private:
int partition(vector<int>& nums, int left, int right) {
int pivot = nums[left], l = left + 1, r = right;
while (l <= r) {
//逆序策略
if (nums[l] < pivot && nums[r] > pivot) {
swap(nums[l++], nums[r--]);
}
if (nums[l] >= pivot) {
l++;
}
if (nums[r] <= pivot) {
r--;
}
}
swap(nums[left], nums[r]);
return r;
}
};