网站上的验证码怎么做网站营销策略有哪些
题目链接
题目描述
给你一个整数数组 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 个高频元素的集合是唯一的
题解
思路
要求频率前k个高的元素的元素,很自然的就是先想到用map来收集每个元素出现的频率,然后对这些频率进行排序
所以这道题的难点就转化成了,怎么对频率进行排序?
这道题考察的是优先级队列的知识点
什么是优先级队列?
队列进出的顺序按照优先级,而不是进入的前后顺序
举个例子: 医院中处理病人不是按照病人来的顺序,而是根据病情的严重程度
我们需要找到频率前k高的元素,可以选择维护一个大小为k的堆,使堆里面的元素总是前k个大的。
那么要使用小顶堆还是大顶堆呢?
在小顶堆中,每次弹出的元素都是堆中最小的元素,堆中剩的是大的;大顶堆中,每次弹出的元素都是堆中最大的元素,堆中剩的是小的。
所以我们要选择小顶堆。
c++中恰好提供了这样一种队列,即priority_queue,队列内部的元素总是有序的,按照元素的权值进行排序。
所以我们可以设置一个大小为k的优先队列,遍历Map的过程中去维护这个队列。最后队列里面剩下的就是前k个出现频率最高的元素啦
代码书写
class MyComparison{
public:bool operator()(const pair<int,int>&m,const pair<int,int>&n){return m.second>n.second;}
};
class Solution {
public:vector<int> topKFrequent(vector<int>& nums, int k) {unordered_map<int,int>myMap;vector<int>re(k);for(int i =0;i<nums.size();i++){myMap[nums[i]]++;}priority_queue<pair<int,int>,vector<pair<int,int>>,MyComparison>q;for(auto it = myMap.begin();it!=myMap.end();it++){q.push(*it);if(q.size()>k){q.pop();}}for(int i=0;i<k;i++){re[i]=q.top().first;q.pop();}return re;}
};
可能会有像我一样的c++苦手看得眼花缭乱
我现在可以详细的解释一下。
-
为什么采用
unordered_map
去收集每个元素的频率?
因为我们不需要使键是有顺序的,并且unorder_map底层逻辑实现是哈希表,在平均情况下查找效率为O(1) 效率更高 -
priority_queue<pair<int,int>,vector<pair<int,int>>,MyComparison>q;
是什么意思?
第一个模版参数pair<int,int>
代表这个优先级队列中存放的数据是pair<int,int>类型;
第二个模版参数vector<pair<int,int>>
代表这个队列的底层容器是vector<pair<int,int>>
第三个模版参数MyComparison
是一个自定义的类,为什么这里可以直接放一个类呢?
priority_queque的声明如下:
template<class T, // 元素类型class Container = vector<T>, // 底层容器(默认vector)class Compare = less<T> // 比较器类型(默认less<T>)
> class priority_queue;
第三个参数 Compare 必须是一个类型,而不是函数或对象。
例如,less 和 greater 是STL中预定义的类型,它们内部重载了 operator(),因此可以生成函数对象(Functor)
- 为什么要重新写一个类重载()呢?
默认比较器会按 pair 的第一个元素的大小进行排序,而我们需要按第二个元素的大小进行排序,所以需要重写。