347. Top K Frequent Elements 出现频率TopK的元素

347. Top K Frequent Elements 出现频率TopK的元素

桶排序

时间复杂度:O(n) 构建频率字典 O(n) 将数字放置进对应频率下标的桶中 O(n) 从后向前遍历桶,将元素取出到结果中,最后返回结果。最坏情况:O(n)

vector<int> topKFrequent(vector<int>& nums, int k) {
    map<int, int> m;
    for(int num : nums)
        ++m[num];

	// 频率为桶的下标时,桶的长度为数组长度+1
    vector<vector<int> > bucket(nums.size()+1);
    vector<int> res;
    for(const auto &pair : m)
        bucket[pair.second].push_back(pair.first);

    for(int i=bucket.size()-1;i>=0&&res.size()<k;--i) {
        if (bucket[i].size()>0)
            res.insert(res.end(), bucket[i].begin(), bucket[i].end());
    }
    return res;
}

需要注意的边界条件是如果整个数组都是某一个数的话,桶的长度就应该是数组长度 + 1,才能使得桶的下标可以直接用所有可能出现的频率直接索引

哈希字典+大顶堆

时间复杂度:nlog(n-k)

vector<int> topKFrequent(vector<int>& nums, int k) {
    unordered_map<int, int> m;
    for(int num : nums)
        ++m[num];

    priority_queue<pair<int,int>> pq;
    vector<int> res;
    for(const auto& pair : m) {
        pq.push(make_pair(pair.second, pair.first));
        if (pq.size() > m.size()-k) {
            res.push_back(pq.top().second);
            pq.pop();
        }
    }
    return res;
}

思路差不多但是 K 较小的时候这个解法比较好,适用于数据量较大的场景,堆中维护的是频率大的元素,当剩余的输入频次数据不足 K 个的时候即可开始将堆顶元素取出

收获

  • stl 的 vector 与 vector 的合并操作
  • 桶的使用,可以用来进行一些快速分类的操作

#堆 #面试 #桶