代码随想录-41-347.前K个高频元素

目录

  • 前言
    • 题目
  • 1.优先级队列(TopK问题) 小顶堆
      • 思路(定义变量)
    • 2. 本题思路分析(具体可见卡哥链接):
    • 3. 算法实现
    • 4. pop函数的算法复杂度
    • 5. 算法坑点

前言

在本科毕设结束后,我开始刷卡哥的“代码随想录”,每天一节。自己的总结笔记均会放在“算法刷题-代码随想录”该专栏下。
代码随想录此题链接

题目

给你一个整数数组 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 是数组大小。

1.优先级队列(TopK问题) 小顶堆

思路(定义变量)

  • 实现一个优先级队列(priority_queue,在C++的STL中的priority_queue是一个容器适配器,而不是一个容器,也就是说他需要底层容器实现它,而一般默认情况下底层容器是vector)
  • unordered_map来统计元素出现的次数
  • 返回结果是一个vector

2. 本题思路分析(具体可见卡哥链接):

  1. 统计所有元素的出现次数(通过unordered_map存储)
  2. 将元素加入到priority_queue(设置为小顶堆)中(没加入一个元素,priority_queue会进行排序),
  • prirority_queue<数据类型,底层容器类型,比较函数(函数对象)>
    (函数对象(也称为仿函数:指一个类看上去像个函数,具有类似函数的行为,即是仿函数类。 仿函数实现方式:在类中加入重载括号运算符的方法 --> operator() ),函数对象用struct/class结合operator成员函数实现)
  • 自定义数据类型为pair(pair可以看成组成map的一组键值对,C++中pair的用法),
  1. 如果优先级队列容量大于k,则弹出队首元素。
  2. 遍历完毕后,优先级队列中存在的就是最大的K个元素,将其遍历输出到vector对象中, 并返回vector对象。

3. 算法实现

  • 代码:
#include 
#include 
#include 
#include  
using namespace std;
struct comparision{
	bool operator() (const pair<int,int>& left,const pair<int,int>& right){
		return left.second > right.second;
	}
};

vector<int> topKFrequent(vector<int>& nums, int k) {
	//1.统计元素出现的频率
	unordered_map<int,int> map;
	for(int i = 0;i < nums.size();i++){
		map[nums[i]]++;
	}
	//2.通过 优先队列 对于元素进行排序(时间复杂度 n*O(log(k)))
	priority_queue<pair<int,int>,vector<pair<int,int>>,comparision> pri_que;
	for(auto it = map.begin();it != map.end();it++){
		pri_que.push(*it);
		if(pri_que.size() > k){
			pri_que.pop();
		} 
	}
	//3.将优先队列中的元素输出 
	vector<int> result;
	for(int i = 0;i < k;i++){
		result.push_back(pri_que.top().first);
		pri_que.pop();
	}
	return result;
}

int main() {
	int k = 2;
	vector<int> nums = {1,1,1,2,2,3};
	vector<int> vs = topKFrequent(nums,k);
	for(int v: vs){
		cout << v << " ";
	}
}

4. pop函数的算法复杂度

  1. 时间复杂度:O(nlog(k)) (如果排序时不用优先队列,使用快速排序的话,时间复杂度为O(nlog(n)))
  2. 空间复杂度:O(n)

5. 算法坑点

  1. 掌握知识点:
  • 关于优先级队列priority_queue中的第三个参数,如下,
priority_queue<pair<int,int>,vector<pair<int,int>>,comparision> pri_que;

中pri_que的第三个参数comparision,这是一个函数对象。
可以由如下struct结合operator() 成员函数实现 。

struct comparision{
	bool operator() (const pair<int,int>& left,const pair<int,int>& right){
		return left.second > right.second;
	}
};

其中pair是一种模板类型,

pair<int,int> pair1(2,3) ;//初始化
pair1 = pair<int,int>(1,4);//重新赋值
pair.first;//获取第一个值
pair.second;//获取第二个值
  • 关于C++ 关于函数形参中const的作用,主要是让该对象保持只读,一般用在传参时搭配&对象引用上,即可以提升传参时的效率(因为是引用传递,不用向值传递一样在函数中复制一份对象)。
  1. 记住仿函数 里面的operator方法前面要加上public: ,不然作用域默认为private
  2. 仿函数是比较pair的second值,如果不写pair.second,则默认会先比较first
  3. priority_queue的第三个参数,比较priority_queue成员大小的函数对象,只能通过strcut/class结合operator成员函数实现,不能使用函数指针实现

你可能感兴趣的:(算法刷题-代码随想录,算法,c++,开发语言)