Leetcode 347. 前 K 个高频元素

目录

    • 0、题目描述
    • 1、pair的用法
    • 2、优先队列(priority_queue)的用法
    • 3、堆排序的原理
    • 4、decltype
    • 5、rbegin() , rend()
    • 6、本题解题思路
    • 7、代码

0、题目描述

题目链接
给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按任意顺序返回答案。

示例 1:
输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]

示例 2:
输入: nums = [1], k = 1
输出: [1]

1、pair的用法

pair是C++中一种模板类型。每个pair对象可以存储两个值,这两个值可以是不同的数据类型。存储的值可以是基本数据类型也可以是自定义数据类型。

(1)声明命名空间:using namespace std;
(2)定义和初始化

	pair p2(p1); //用已有的对象初始化
	
	pair p3(1, 1.2);
	
	pair p4; //没有显示初始化,自动执行默认初始化操作。p4为(0,0)
	
	make_pair(v1, v2); // 以v1和v2的值创建一个新的pair对象,其元素类型分别是v1和v2的类型。
	
	pair > line;  // 创建一个空对象line,两个元素类型分别是string和vector类型

(3)pair有两个属性:first和second。

	p1.first = 11; //修改第一个数值  
			 
	p1.second =22; //修改第二个数值

2、优先队列(priority_queue)的用法

c++优先队列(priority_queue)用法详解
简单看一下就行了

3、堆排序的原理

堆排序参考一(图文)
堆排序参考二(视频)

4、decltype

这是c++11的特性,decltype类型说明符用于取出变量类型。
decltype可以作用于变量、表达式及函数名。①作用于变量直接得到变量的类型;②作用于表达式,结果是左值的表达式得到类型的引用,结果是右值的表达式得到类型;③作用于函数名会得到函数类型,不会自动转换成指针。
decltype不会去真的求解表达式的值。
【C++深陷】之“decltype”

5、rbegin() , rend()

c++的反向迭代器。begin()和end()分别指向数组的首元素和尾元素的下一位。rbegin()和rend()分别指向尾元素和首元素的前一位;sort(vec.rbegin(), vec.rend());就可以获得降序排列的vec,也就是最小值在尾元素。
(虽然本题没有用到)

6、本题解题思路

(1)本题思路:

  1. 统计元素出现频率 (哈希表map)
  2. 对频率排序
  3. 找出前K个高频元素

(2)本题重点在于用优先级队列来对部分频率进行排序。

  • 使用快排要将map转换为vector的结构,然后对整个数组进行排序, 然而本题只需要维护k个有序的序列就可以了,所以使用优先级队列是最优的。
  • 优先级队列利用堆完成排序,本题因为需要保留的是高频元素,也就是数值更大的元素,故采用小顶堆,每次构建堆之后都将最小的元素从根结点弹出去,所以剩下的就是较大值的元素。

(3)优先队列不用greater

  • 考虑过使用:priority_queue, vector>, greater>> pri;,greater小顶堆本以为能得到正确答案。

  • 其实这样无法进行正确的排序,是因为emplace操作默认是比较first,而频数位于second;因此需要自定义比较函数将second作为唯一优先级。

(4)有看到另一种解法:本题的困扰在于pair用的是first来进行排序,那么我们可以将频数保存在first,将num保存在second。①定义一个vector,数据类型为pair,记为s。②不需要使用哈希表,先将nums数组排序,然后直接遍历nums获得某个数的频次(已经排序的数组重复数字必然是连续存放的)将其保存在first。③将s进行反向排序(用到rbegin() , rend()),然后只弹出前k个元素即可。

7、代码

class Solution {
public:
        //1,自定义compare函数
    static bool cmp(pair<int, int>& l, pair<int, int>& r) {
        return l.second > r.second;
    }
    vector<int> topKFrequent(vector<int>& nums, int k) {
        //2,使用哈希表存储各个数据的频次
        unordered_map<int, int> hashmap;
        for(auto& num : nums) {
            hashmap[num]++;
        }
        //3,使用优先队列+小顶堆来对频次排序
        priority_queue<pair<int, int>, vector<pair<int, int>>, decltype(&cmp)> pri(cmp);
        for(auto& [num, count] : hashmap) {
            if(pri.size() == k) {
                if(pri.top().second < count) {
                    pri.pop();
                    pri.emplace(num, count);
                }
            }
            else pri.emplace(num, count);
        }
        //4,取出前K个高频元素
        vector<int> res;
        while(!pri.empty()) {
            res.push_back(pri.top().first);
            pri.pop();
        }
        return res;
    }
};

你可能感兴趣的:(刷题,leetcode,算法,堆排序,队列,c++)