215. Kth Largest Element in an Array(数组中第k大元素)
题目链接
https://leetcode.com/problems/kth-largest-element-in-an-array/description/
题目描述
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.
题目分析
这是一个非常常见的题目,解法少说也有五六种。我这里只介绍两种,一种是利用SQL写起来非常简单,几行代码就可以轻松搞定;另一种是时间复杂度较低,写起来略微复杂一点。
方法一:优先队列
算法描述
- 遍历数组,维护一个长度不超过k的优先队列,当队列长度小于k时,当前元素进队;当队列长度等于k时,当前元素和队列中最小元素比较,若大于队列中最小元素,则最小元素出队,当前元素进队。
- 遍历结束后,队列中的最小元素即位数组中第k大元素
方法二:分治算法(利用快排思想)
算法描述
- 快排分为三个阶段:分解,解决,合并1( 分解:数组
A[p..r]
被划分为两个(可能为空)子数组A[p..q-1]
和A[q+1..r]
,使得A[p..q-1]
中的每一个元素都小于等于A[q]
,而A[q]
也小于等于A[q+1..r]
中的每个元素。) - 这里只用到分解。分解之后,我们可以知道比
A[q]
大的数字的个数,与k
作比较:
- 若个数大于
k-1
:则问题变为在A[q+1..r]
中寻找第k
大的元素 - 若个数等于
k-1
:则第k
大元素为A[q]
- 若个数小于
k-1
:则问题变为在A[p..q-1]
中寻找第k-r+q-1
大的元素
- 若个数大于
参考代码
方法一:优先队列
class Solution {
public:
int findKthLargest(vector<int>& nums, int k) {
priority_queue<int, vector<int>, greater<int> > queue;
for (int i = 0; i < nums.size(); i++) {
if (queue.size() < k)
queue.push(nums[i]);
else if (queue.top() < nums[i]) {
queue.pop();
queue.push(nums[i]);
}
}
return queue.top();
}
};
方法二:分治算法(利用快排思想)
class Solution {
public:
int findKthLargest(vector<int>& nums, int k) {
if (nums.size() == 1) return nums[0];
vector<int>::iterator pivot = nums.end() - 1;
int i = -1, temp;
for (auto j = nums.begin(); j != nums.end() - 1; j++)
if (*j < *pivot) {
i++;
temp = nums[i];
nums[i] = *j;
*j = temp;
}
temp = nums[i + 1];
nums[i + 1] = *pivot;
*pivot = temp;
if (nums.size() - i - 1 > k) {
for (int p = 0; p <= i + 1; p++) {
auto tmp = nums.begin();
nums.erase(tmp);
}
return findKthLargest(nums, k);
}
else if (nums.size() - i - 1 == k) {
return nums[i + 1];
} else {
int tmp = k - nums.size() + i + 1;
while (nums.size() > i + 1)
nums.pop_back();
return findKthLargest(nums, tmp);
}
}
};
结语
事实上,方法二的代码并没有方法一的代码跑得快。我分析因为一方面的原因是递归是一种耗时的方法(建立新的函数栈,结束后销毁函数栈……);另一方面的原因是本来不需要对数组做删除元素的操作,只需要在递归的时候传递边界下标,但这道题目给定了参数列表,只能这么写了。
- 算法导论(原书第3版)/(美)科尔曼(Cormen, T.H.)等著;殷建平等译. —北京:机械工业出版社,2013.1,第95-97页 ↩