LeetCode347.前 K 个高频元素

347.前 K 个高频元素

文章目录

      • 347.前 K 个高频元素
        • 一、题目
        • 二、解法
          • 方法一:哈希表+数组
          • 方法二:优先队列
            • 算法思路
            • 具体实现
            • 算法分析
        • 三、拓展(方法二里优先队列声明)


一、题目

数组 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 是数组大小。

二、解法

方法一:哈希表+数组

算法思路:

本题的关键是要找到数组中出现频率最高的K个元素。一个直观的思路是使用哈希表记录每个元素出现的次数,然后对记录的次数进行排序,取出次数最多的K个元素即可。

具体步骤是:

  1. 遍历数组,使用哈希表记录每个元素出现的次数
  2. 将记录的元素次数节点放入vector中
  3. 对vector进行排序,排序规则是按出现次数降序
  4. 从排序后的vector取出前K个元素,这就是TOP K个高频元素

具体实现:

  1. 使用哈希表nums_map记录每个元素出现的次数
  2. 遍历数组,统计每个元素出现的次数
  3. 将哈希表中的记录节点转化为pair对,存入vec向量中
  4. 利用sort对vec进行排序,排序规则通过compare函数指定为对第二个元素降序排序
  5. 从vec中取出前k个pair,并将first元素放入result中

这里的关键点是compare函数指定了排序规则,并且sort后的vec并不是我们直接要的结果,而是需要从中提取出top k的first元素。

class Solution {
public:
    static bool compare(const pair<int,int>& v1,const pair<int,int>& v2){
        return v1.second > v2.second;
    }
    vector<int> topKFrequent(vector<int>& nums, int k) {
        map<int,int> nums_map;
        vector<int> result;
        vector<pair<int,int>> vec;
        for(int i = 0; i < nums.size(); i++){
            nums_map[nums[i]]++;
        }
        for(auto it = nums_map.begin(); it != nums_map.end(); it++){
            vec.push_back(make_pair(it->first,it->second));
        }

        sort(vec.begin(), vec.end(), compare); 

        for(int i = 0; i < k; i++) {
            result.push_back(vec[i].first); 
        }

        return result;
    }
};

算法分析:

  • 时间复杂度为O(NlogN),遍历数组为O(N),排序为O(NlogN)
  • 空间复杂度为O(N),哈希表存储为O(N),vec向量存储也为O(N)
方法二:优先队列
算法思路

这个算法的核心思路是利用哈希表统计元素频率,并维护一个大小为 K 的最小堆,final结果储存在最小堆里。具体步骤如下:

  1. 使用哈希表统计每个元素出现的频率
  2. 将统计结果以 pair 对的形式插入最小堆
  3. 堆的大小维持为 K
  4. 堆首元素弹出,代表频率最小的元素
  5. 最后最小堆里剩下的 K 个元素就是题目要求的 Top K 个高频元素

最小堆的排序规则通过自定义 compare 函数实现。

具体实现
  1. 使用 map 统计每个元素的频率
  2. 使用 priority_queue 声明一个最小堆,自定义比较函数 compare
  3. 遍历 map,用 pair 对封装元素和频率,插入到最小堆
  4. 堆的大小超过 K 时,弹出堆顶元素
  5. 结果数组通过最小堆的 top() 函数获取
class Solution {
public:
    static bool compare(const pair<int,int>& v1,const pair<int,int>& v2){
        return v1.second > v2.second;
    }
    vector<int> topKFrequent(vector<int>& nums, int k) {
        map<int,int> nums_map;
        for(int i = 0; i < nums.size(); i++){
            nums_map[nums[i]]++;
        }
       priority_queue<pair<int,int>, vector<pair<int,int>>, decltype(&compare)> pri_que(compare);//建立最小优先队列
        for(map<int,int>::iterator it = nums_map.begin();it != nums_map.end();it++){
            pri_que.push(*it);
            if(pri_que.size() > k){
                pri_que.pop();
            }
        }
        //写入结果数组
        vector<int> result(k);
        for(int i = k-1; i >= 0; i--){
            result[i] = pri_que.top().first;
            pri_que.pop();
        }
        return result;
    }
};
算法分析
  • 时间复杂度为 O(NlogK),统计频率 O(N),维护堆 O(NlogK)
  • 空间复杂度为 O(N),map 存储频率 O(N),优先队列空间 O(K)

三、拓展(方法二里优先队列声明)

方法二里优先队列的声明是:

priority_queue<pair<int,int>, vector<pair<int,int>>, decltype(&compare)> pri_que(compare);

这个语句中:

  • priority_queue 表示声明一个优先队列
  • , vector> 指定了优先队列的模板参数,第一个是元素类型,第二个是底层容器类型
  • decltype(&compare) 是比较函数的类型
  • > 表示模板参数列表结束
  • pri_que 是优先队列的变量名
  • (compare) 是以比较函数作为参数构造优先队列

pri_que(compare) 则表示以 compare 函数为参数构造这个优先队列,将排序规则传入。

你可能感兴趣的:(Leetcode刷题,leetcode,栈和队列)