前K个高频元素——栈与队列
先放代码:
class Solution {
public:
class mycomperation {
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> umap;
for (int i = 0; i < nums.size(); i++) {
umap[nums[i]]++;
}
// 定义好了之后,开始维护小顶堆
priority_queue<pair<int, int>, vector<pair<int, int>>, mycomperation> myque;
// 开始排序
for (unordered_map<int, int>::iterator it = umap.begin(); it != umap.end(); it++) {
myque.push(*it); // 所以其实可以把迭代器理解为一个指针类型
// 我们只需要维护k个元素即可
if (myque.size() > k) {
myque.pop();
}
}
// 维护好了之后就是结果的输出,注意是倒序输出
vector<int> result;
for (int i = k - 1; i >= 0; i--) {
result.push_back(myque.top().first);
myque.pop();
}
return result;
}
};
里面用到的东西很多,涉及到了运算符重载,比较器,堆,优先级队列,哈希表等内容。一个一个来。
1、运算符重载
在 C++ 中,operator()
被称为 函数调用运算符。它允许我们像调用函数一样调用类的对象。也就是说,如果一个类重载了 operator()
,那么你可以像调用函数一样,通过 ()
来调用这个类的实例。
而一般我们常用运算符重载的方式来构建堆的比较器,这样堆就可以使用类内的这个重载过的运算符。
2、堆的比较器
堆的比较器:我们使用 operator()
来定义堆中元素的比较规则。比较器是一个“函数对象”,可以让你自定义堆的排序方式。
3、堆
堆可以理解为一个完全二叉树,就是节点都是满的,而且最下面的节点尽可能靠左。然后堆又分为大顶堆和小顶堆,一个是从大到小一个是从小到大。然后通常通过 优先队列(std::priority_queue
) 来实现。std::priority_queue
默认是最大堆(即堆顶是最大的元素),但可以通过自定义比较器来实现最小堆或其他排序规则。
4,优先级队列
C++ STL 提供了一个容器适配器 std::priority_queue
,可以用来实现优先级队列。默认情况下,std::priority_queue
是一个最大优先级队列(即堆顶元素为最大值)。它使用 二叉堆 来实现,因此插入和删除操作的时间复杂度为 O(log n)。
// 使用自定义的比较器创建一个最小优先级队列 std::priority_queue<int, std::vector<int>, MinComparator> pq;
5.哈希表
这个是前面内容,简单回顾一下unordered_map是无序的,然后我们一般遍历里面的内容时采用迭代器的方式,注意
for (unordered_map<int, int>::iterator it = umap.begin(); it != umap.end(); it++)
差不多就这些、