[leetcode] 347. Top K Frequent Elements

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

For example,
Given [1,1,1,2,2,3] and k = 2, return [1,2].

Note: 

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

这道题是找数组中前K个数量最多的元素,题目难度为Medium。


比较直观的想法是用Hash Table统计元素个数,然后用堆来找出前K个数量最多的元素。priority_queue默认是大根堆,所以可以将<计数-元素>对直接存入堆中。具体代码:

class Solution {
public:
    vector<int> topKFrequent(vector<int>& nums, int k) {
        unordered_map<int, int> hash;
        priority_queue<pair<int,int>> heap;
        vector<int> ret;
        
        for(int num:nums) 
            hash[num]++;
        
        for(auto it:hash) 
            heap.push(make_pair(it.second, it.first));
        
        for(int i=0; i<k; ++i) {
            ret.push_back(heap.top().second);
            heap.pop();
        }
        
        return ret;
    }
};

虽然解决了题目,但是时间复杂度达到了O(nlogn),因为建堆的时间复杂度是O(logn),题目要求时间复杂度优于 O(nlogn),因此还需要优化。这里可以用小根堆取代大根堆,在堆元素超过K时,删除堆顶元素,因为它不可能是数量最多的K个元素之一,遍历完所有数组元素之后堆中剩下的K个元素即是所求结果。优化后时间复杂度为O(nlogK)。具体代码:
class Solution {
    typedef pair<int, int> data;
public:
    vector<int> topKFrequent(vector<int>& nums, int k) {
        unordered_map<int, int> hash;
        priority_queue<data, vector<data>, greater<data>> heap;
        vector<int> ret;
        
        for(int num:nums) 
    ​    ​    ​hash[num]++;
        
        for(auto it:hash) {
            heap.push(make_pair(it.second, it.first));
            if(heap.size() > k) heap.pop();
        }
        
        while(!heap.empty()) {
            ret.push_back(heap.top().second);
            heap.pop();
        }
        
        return ret;
    }
};

另外看到有人通过桶排序来解决问题,顺便介绍一下这种方法。桶排序的基本思想就不讲了,不清楚的同学可以问度娘。假设数组共有N个元素,用编号为1~N的N个桶分别存储个数为桶号个的元素,统计完成后从第N个桶开始从后向前依次取桶中元素,直至取够K个元素即得到了结果。具体代码:
class Solution {
public:
    vector<int> topKFrequent(vector<int>& nums, int k) {
        unordered_map<int, int> hash;
        vector<vector<int>> buckets(nums.size()+1);
        vector<int> ret;
        
        for(int num:nums) 
    ​    ​    ​hash[num]++;
        
        for(auto it:hash) 
    ​    ​    ​buckets[it.second].push_back(it.first);
        
        for(int i=buckets.size()-1; i>0; --i) {
            for(auto num:buckets[i]) {
                ret.push_back(num);
                if(ret.size() == k) return ret;
            }
        }
        
        return ret;
    }
};

题目中没有说明类似[1, 1, 1, 2, 2, 3, 3],K=2这种情况下返回[1, 2]还是[1, 3],就先当做都正确处理吧。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值