Top K Frequent Elements

406 篇文章 0 订阅
406 篇文章 0 订阅

1,题目要求

Given a non-empty array of integers, return the k most frequent elements.

Example 1:
Input: nums = [1,1,1,2,2,3], k = 2
Output: [1,2]

Example 2:
Input: nums = [1], k = 1
Output: [1]

Note:

  • You may assume k is always valid, 1 ≤ k ≤ number of unique elements.
  • Your algorithm’s time complexity must be better than O(nlogn), where n is the array’s size.

给定非空的整数数组,返回k个最常见的元素。

2,题目思路

对于这道题,要求求一个数组中出现频率前k个元素。因此,这道题首先就需要对每个元素出现的次数进行统计和计算。

在统计元素的个数上,使用容器map是一个非常快捷的办法。

之后,我们需要找到出现次数在前k个的数字。
如果我们可以直接对map的second元素进行排序,结果将会非常的简单,但是map不可以使用sort方法,因此,我们必须人为地去找到前k频繁的元素。

在如何实现这个功能上,我们这里有两种方法:
第一种方法,是利用C++内置的一种容器:
priority_queue,优先队列
对于这个容器,之后会单独写一篇博客做学习记录。
这里只需要知道,它是一种堆结构,在构建的过程中,会按照一定的顺序来构建,有点类似于map的构建过程(map是基于红黑树)。
因此,在构建这个优先队列时,根据map中的second元素,默认会构建一个大顶堆。
构建完成之后,取前k个元素的first的值,就可以得到对应的前k个最频繁的元素。

第二种方法,则是使用桶排序的方法。
这种方法也比较直观。
同样的,在使用map实现记录每个元素出现的次数之后,构建一个二维向量,利用桶的思路,将出现的次数作为索引,每个索引对应出现这个次数的数字。
从后往期按顺序将这些数字加入到返回数组中,当返回数组的长度达到k时,就说明找到了前k最频繁的元素,返回即可。

3,代码实现

1,priority_queue

int x = []() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
    return 0;
}();

class Solution {
public:
    vector<int> topKFrequent(vector<int>& nums, int k) {
        map<int, int> frequentMap;
        for(auto &n : nums)
            frequentMap[n]++;   //统计数组中每个数字出现的次数
        
        //利用优先队列中的特点来取前k
        //默认构建大顶堆
        priority_queue<pair<int, int>> q;
        for(auto &fm : frequentMap)
            q.push(make_pair(fm.second, fm.first));
        
        vector<int> res;
        while(k--){
            res.push_back(q.top().second);
            q.pop();
        }
        
        return res;
    }
};

2,桶排序

class Solution {
public:
    vector<int> topKFrequent(vector<int>& nums, int k) {
        int maxVal = INT_MIN;
        unordered_map<int, int> frequentMap;
        for(auto &n : nums){
            frequentMap[n]++;
            maxVal = max(maxVal, frequentMap[n]);
        }
        
        vector<vector<int>> backet (maxVal+1);
        for(auto &fm : frequentMap)
            backet[fm.second].push_back(fm.first);
        
        vector<int> res;
        for(int i = maxVal;i>=0 && res.size()<k;i--){
            for(auto &n : backet[i]){
                res.push_back(n);
                if(res.size() == k)
                    break;
            }
        }
        return res;
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值