文章目录
力扣刷题日志——347. 前 K 个高频元素
题干
给你一个整数数组 nums
和一个整数 k
,请你返回其中出现频率前 k
高的元素。你可以按 任意顺序 返回答案。
示例 1:
输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]
示例 2:
输入: nums = [1], k = 1
输出: [1]
提示:
1 <= nums.length <= 105
k
的取值范围是[1, 数组中不相同的元素的个数]
- 题目数据保证答案唯一,换句话说,数组中前
k
个高频元素的集合是唯一的
**进阶:**你所设计算法的时间复杂度 必须 优于 O(n log n)
,其中 n
是数组大小。
思路
- 计算出元素出现的频率(考虑使用map)
- 按元素出现次数进行排序(优先级队列)
- 输出频率前k高的元素
什么是优先级队列(priority_queue)?
一个披着队列外衣的堆
对外接口只是从队头取元素,从队尾添加元素,再无其他取元素的方式,看起来就是一个队列
内部实现
默认情况下,利用max-heap(大根堆)完成对元素的排序。这个大根堆是以vector为表现形式的complete binary tree(完全二叉树)
为什么这道题不用大根堆而是小根堆?
因为,我们限定优先级队列的大小为k后,要留下频率最高的k个数,因此,使用小根堆pop出较小的数,留下的就是频率最大的k个数,这里也没有对输出数组的顺序有要求。
如何使用小根堆优先级队列?
int
#include <iostream>
#include <queue>
using namespace std;
void showpq( priority_queue<int, vector<int>, greater<int> > g) {
while (!g.empty()) {
cout << ' ' << g.top();
g.pop();
}
cout << '\\n';
}
void showArray(int* arr, int n) {
for (int i = 0; i < n; i++) {
cout << arr[i] << ' ';
}
cout << endl;
}
int main() {
int arr[6] = { 10, 2, 4, 8, 6, 9 };
priority_queue<int, vector<int>, greater<int> > gquiz( arr, arr + 6);
cout << "Array: ";
showArray(arr, 6);
cout << "Priority Queue : ";
showpq(gquiz);
return 0;
}
自定义对象
struct Person {
int age;
};
struct LessThanByAge {
bool operator()(const Person& lhs, const Person& rhs) const {
return lhs.age > rhs.age;
}
};
priority_queue<Person, vector<Person>, LessThanByAge> pq;
在这个例子中,LessThanByAge是一个自定义的比较函数,它将Person对象按照age属性的大小进行排序。这样,pq.top()将返回age最小的Person对象。如果你想让age最大的Person在顶部,你可以改变LessThanByAge操作符的实现
代码实现:
class myComparison
{
public:
bool operator()(const pair<int, int>& lhs, const pair<int, int>& rhs) const
{
return lhs.second > rhs.second;
}
};
class Solution {
public:
vector<int> topKFrequent(vector<int>& nums, int k) {
//统计出现的频次
unordered_map<int,int> map;
for(auto num : nums)
{
map[num]++;
}
// 定义一个小顶堆,大小为k
priority_queue<pair<int,int>,vector<pair<int,int>>,myComparison> pri_que;
for(unordered_map<int,int>::iterator it = map.begin(); it != map.end(); ++it)
{
pri_que.push(*it);
if(pri_que.size() > k)
{
pri_que.pop();
}
}
vector<int> ret(k);
for(int i = k - 1; i >= 0; --i)
{
ret[i] = pri_que.top().first;
pri_que.pop();
}
return ret;
}
};