前K个高频元素
Posted 差生_G
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了前K个高频元素相关的知识,希望对你有一定的参考价值。
数据结构--堆
Heap是一种数据结构具有以下的特点:
1)完全二叉树;
2)heap中存储的值是偏序;- Min-heap: 父节点的值小于或等于子节点的值;
Max-heap: 父节点的值大于或等于子节点的值;
1.堆的存储:
一般都用数组来表示堆,i结点的父结点下标就为(i–1)/2。它的左右子结点下标分别为2 * i + 1和2 * i + 2。如第0个结点左右子结点下标分别为1和2
2.堆的操作:insert
插入一个元素:新元素被加入到heap的末尾,然后更新树以恢复堆的次序。
每次插入都是将新数据放在数组最后。可以发现从这个新数据的父结点到根结点必然为一个有序的数列,现在的任务是将这个新数据插入到这个有序数据中——这就类似于直接插入排序中将一个数据并入到有序区间中。
3.堆的操作:Removemax
按定义,堆中每次都删除第0个数据。为了便于重建堆,实际的操作是将最后一个数据的值赋给根结点,然后再从根结点开始进行一次从上向下的调整。调整时先在左右儿子结点中找最大的,如果父结点比这个最小的子结点还大说明不需要调整了,反之将父结点和它交换后再考虑后面的结点。相当于从根结点将一个数据的“下沉”过程。
4.堆的操作:buildHeap 堆化数组
对于叶子节点,不用调整次序,根据满二叉树的性质,叶子节点比内部节点的个数多1.所以i=n/2 -1 ,不用从n开始
5.堆排序
堆建好之后堆中第0个数据是堆中最大的数据。取出这个数据再执行下堆的删除操作。这样堆中第0个数据又是堆中最大的数据,重复上述步骤直至堆中只有一个数据时就直接取出这个数据。
priority_queue
priority_queue允许用户为队列中元素设置优先级,放置元素的时候不是直接放到队尾,而是放置到比它优先级低的元素前面,标准库默认使用<操作符来确定优先级关系。
priority_queue模板类有三个模板参数:元素类型,容器类型,比较算子。其中后两个可以省略,默认容器为vector,默认算子为less,即如果x<y判断为真,则y排到x前面,y先出队。
priority_queue<int,vector
,greater > q3;//定义优先级小的先出队 priority_queue与queue的基本操作均相同,在使用q.top()时返回最高优先级的元素,该操作只适用于优先级队列。
pair
pair是将2个数据组合成一个数据,当需要这样的需求时就可以使用pair,如stl中的map就是将key和value放在一起来保存。另一个应用是,当一个函数需要返回2个数据的时候,可以选择pair。 pair的实现是一个结构体,主要的两个成员变量是first second 因为是使用struct不是class,所以可以直接使用pair的成员变量。
make_pair函数:
template pair make_pair(T1 a, T2 b) { return pair(a, b); }
很明显,我们可以使用pair的构造函数也可以使用make_pair来生成我们需要的pair。 一般make_pair都使用在需要pair做参数的位置,可以直接调用make_pair生成pair对象很方便,代码也很清晰。 另一个使用的方面就是pair可以接受隐式的类型转换,这样可以获得更高的灵活度。
类模板:template <class T1, class T2> struct pair
参数:T1是第一个值的数据类型,T2是第二个值的数据类型。
功能:pair将一对值组合成一个值,这一对值可以具有不同的数据类型(T1和T2),两个值可以分别用pair的两个公有函数first和second访问。
- 生成新的pair对象
可以使用make_pair对已存在的两个数据构造一个新的pair类型:
int a = 8;
string m = "James";
pair<int, string> newone;
newone = make_pair(a, m);
using 别名指定
在C++11中提出了通过using指定别名
using value_type = _Ty
以后使用value_type value; 就代表_Ty value;
库
#include <bits/stdc++.h>
开始今天的题目
给定一个非空的整数数组,返回其中出现频率前 k 高的元素。
示例 1:
输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]
示例 2:
输入: nums = [1], k = 1
输出: [1]
说明:
你可以假设给定的 k 总是合理的,且 1 ≤ k ≤ 数组中不相同的元素的个数。
你的算法的时间复杂度必须优于 O(n log n) , n 是数组的大小。
解析:
topk (前k大)用小根堆,维护堆大小不超过 k 可。每次压入堆前和堆顶元素比较,如果比堆顶元素还小,直接扔掉,否则压入堆。检查堆大小是否超过 k,如果超过,弹出堆顶。复杂度是 nlogk
避免使用大根堆,因为你得把所有元素压入堆,复杂度是 nlogn,而且还浪费内存。如果是海量元素,那就挂了。
[注意]
求前 k 大,用小根堆,求前 k 小,用大根堆。面试的时候如果说反了会挂!
代码
class Solution {
public:
vector<int> topKFrequent(vector<int>& nums, int k) {
using E = pair<int,int>;
priority_queue<E,vector<E>,greater<E>> minHeap;//优先级小的在栈顶,即值小的先出栈
map<int,int> counter;
for(auto e :nums){
++counter[e];//记录出现的频率
}
for(auto & x:counter){//加个引用如果需要改变X的值就必须得有
auto pair = make_pair(x.second,x.first);
if(minHeap.size() == k){//保证前K
if(pair < minHeap.top()) continue;
minHeap.pop();
}
minHeap.push(pair);
}
vector<int> res (minHeap.size());
k = res.size();
while(!minHeap.empty()){
res[--k] = minHeap.top().second;
minHeap.pop();
}
return res;
}
};
以上是关于前K个高频元素的主要内容,如果未能解决你的问题,请参考以下文章