![](https://i-blog.csdnimg.cn/blog_migrate/8f6ef6190633e40cc51202c1e6dbd8b2.png)
// 时间复杂度:O(nlogk)
// 空间复杂度:O(n)
class Solution {
public:
//使用小顶堆,将前面的pop,剩下的K个就是频率最高的k个
//不使用大顶堆的原因是每次加入新元素时要将堆顶元素pop,则会将频率最高的元素pop
//仿函数(Functor)
//仿函数类都必须重载()运算符
//例如下面的类,在对其进行实例化时调用其构造函数,此时就会执行重载后的()函数体
//具体在优先级队列中时怎么执行的不看源码不清楚
class mycomparison{//表示频率小的优先级大
public:
//为什么要重载()啊?不懂
bool operator()(const pair<int,int> &lhs, const pair<int,int> &rhs){
return lhs.second>rhs.second;
}
};
vector<int> topKFrequent(vector<int>& nums, int k) {
//统计每个元素的频率
unordered_map<int,int> map;
for(int i=0;i<nums.size();i++)
{
map[nums[i]]++;
}
//优先级队列priority_queue:保证每次的队首元素都是优先级最大的
//底层是通过堆来实现的
//定义一个小顶堆
priority_queue<pair<int,int>,vector<pair<int,int>>,mycomparison> pri_que;
//遍历map,将键值对放入优先级队列
for(auto it:map)
{
pri_que.push(it);
if(pri_que.size()>k)//保持优先级队列中始终为当前频率最高的前k个元素
{
pri_que.pop();
}
}
//最后小顶堆中剩余的K个元素即频率最高的前k个元素
vector<int> res;
while(!pri_que.empty())
{
res.push_back(pri_que.top().first);
pri_que.pop();
}
return res;
}
};
![](https://i-blog.csdnimg.cn/blog_migrate/5794f34bc3b14fa9cda21ca9c5641ca8.png)
class Solution {
public:
class mycomparison{
public:
bool operator()(const pair<string,int> &l,const pair<string ,int> &r)
{
//按字典顺序是当两个频率相等时,对first进行排序
//按字典顺序要倒序,因为这是小顶堆
return l.second==r.second?l.first<r.first:l.second>r.second;
}
};
vector<string> topKFrequent(vector<string>& words, int k) {
//统计单词频率
unordered_map<string,int> m;
for(auto str:words)
{
m[str]++;
}
//建立小顶堆
priority_queue<pair<string,int>,vector<pair<string,int>>,mycomparison> smallTopPile;
//遍历map,将其全部元素push进小顶堆
for(auto it:m)
{
smallTopPile.push(it);
if(smallTopPile.size()>k)//保证小顶堆中始终是前K个频率最高的元素
{
smallTopPile.pop();
}
}
//这里注意,在输出结果时是要倒序输出的!
vector<string> res(k);
int i=k-1;
while(!smallTopPile.empty())
{
res[i]=smallTopPile.top().first;
smallTopPile.pop();
i--;
}
return res;
}
};