前k个大数问题
所谓前k个大数问题,一般是指求第k个大的元素,或者出现频率第k高的元素,这种题一般用优先队列比较好解决,有时候需要结合哈希表先把元素存储下来,可能还要重写优先队列排序函数。
347. 前 K 个高频元素
/**
* 解题思路:先把nums中的元素频率存储在哈希表中,键值为元素值,实值为频率,然后把哈希表中的元素压入优先队列中,最后取优先队列前k个
*/
class Solution {
private:
class ComPair {
public:
bool operator () (const pair<int, int> &left, const pair<int, int> &right) {
return left.second < right.second;
}
};
public:
vector<int> topKFrequent(vector<int>& nums, int k) {
unordered_map<int, int> fre;
for (int i : nums)
fre[i]++;
priority_queue<pair<int, int>, vector<pair<int, int>>, ComPair> priQue;
for (auto &i : fre)
priQue.push(i);
vector<int> ans(k);
for (int i = 0; i < k; i++) {
ans[i] = priQue.top().first;
priQue.pop();
}
return ans;
}
};
其实这里代码写的还不完善,可以使用一个最小堆,这样时间复杂度可以控制在O(logn * k),使用最大堆需要对所有元素进行排序。
215. 数组中的第K个最大元素
这个就比较简单,直接用优先队列就行。
class Solution {
public:
int findKthLargest(vector<int>& nums, int k) {
priority_queue<int, vector<int>, greater<int>> smallQue;
for (int i : nums) {
smallQue.push(i);
if (smallQue.size() > k)
smallQue.pop();
}
return smallQue.top();
}
};
692. 前K个高频单词
这题倒和第一题差不多,不过有一个坑的地方,就是题目说如果不同单词频率相同,则按字典序排序,意思是如果频率相同,字典序小的排在前面,而不是大的排在前面,所以写排序函数的时候要注意一下。
class Solution {
private:
class ComPair {
public:
bool operator () (const pair<string, int> &left, const pair<string, int> &right) {
if (left.second != right.second)
return left.second > right.second;
else
return left.first < right.first;
}
};
public:
vector<string> topKFrequent(vector<string>& words, int k) {
unordered_map<string, int> fre;
for (string &s : words)
fre[s]++;
priority_queue<pair<string, int>, vector<pair<string, int>>, ComPair> smallHeap;
for (auto &i : fre) {
smallHeap.push(i);
if (smallHeap.size() > k)
smallHeap.pop();
}
vector<string> ans(k);
for (int i = k - 1; i >= 0; i--) {
ans[i] = smallHeap.top().first;
smallHeap.pop();
}
return ans;
}
};
总结
这种前k个大数问题一般都可以用优先队列来做(其实有时候用快排做也行)。