347.前 K 个高频元素
力扣题目链接(opens new window)
给定一个非空的整数数组,返回其中出现频率前 k 高的元素。
示例 1:
- 输入: nums = [1,1,1,2,2,3], k = 2
- 输出: [1,2]
示例 2:
- 输入: nums = [1], k = 1
- 输出: [1]
思路
解题步骤大概如下:
- 统计频率
- 排序频率
- 提取前k个
统计我们可以用容器map,排序是比较大的问题。如果我们使用map来排序的话,就需要将其转换成vector后排序,复杂度比较高。
我们可以使用priority_queue(优先级队列,优先级队列即看起来是个队列,实际上底层实现是用一个堆,也即完全二叉树,这个结构的特点是父节点的值大于或小于子节点的值,因此又分为大顶堆和小顶堆,顾名思义,大顶堆就是数值大的在最顶层,小顶堆则是反过来。而priority_queue就是用这样原理的一个数据结构,我们可以直接使用。
排序频率我们已经实现了,有一个问题是选择大顶堆还是小顶堆。一般人肯定是毫不犹豫选择大顶堆,但是如果是大顶堆,那么每一次遇到比顶要大的元素,就需要将顶下面的所有节点排列一遍,这样非常麻烦。
如果我们使用小顶堆,则数量超过k个时就pop,这样堆里头永远只有k个,也即前k个。
代码如下
class MyCpy{
public:bool operator()(const pair<int,int>& p1, const pair<int,int>& p2){return p1.second>p2.second;}
};
class Solution {
public:vector<int> topKFrequent(vector<int>& nums, int k) {map<int,int>nums_map;for(int val:nums){nums_map[val]++;}vector<int> res;priority_queue<pair<int,int>,vector<pair<int,int>>, MyCpy> pri_que;for (auto c:nums_map) {pri_que.push(c);if (pri_que.size()>k){pri_que.pop();}}for (int i = k-1; i >= 0 ; --i) {res.push_back(pri_que.top().first);pri_que.pop();}return res;}
};