题目: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个元素。

要求复杂度要小于O(nlogn)

思路:

首先,需要求出每个数的频度,可以使用map,这样只用遍历数组一次,就求出每个数的频度。

然后找到频度最大的k个元素,返回。

如何找到频度最大的k个元素呢?

最直接的思路就是对上面得到的频度排序,这样就能得到频度最大的k个元素,但是排序算法的复杂度可能会变成O(n^2)。

因此,应该还有更好的方法。

我的思路是使用优先队列,保证队列中元素数量最大只有k个,这样直接返回优先队列中的元素就可以了。

而且,优先队列会自动根据一个值排序,我希望按照频度来排序。

当优先队列中已有k个元素时,每次新的元素要和频度最小的元素比较,取频度较大的元素。这样优先队列顶端的必须是频度最小的元素,所以我去频度的负数来做比较。

优先队列是使用堆来实现的,每次插入元素是一个调整堆的过程,时间复杂度是O(logn)。所以这样时间复杂度必然是小于O(nlogn)的。

vector<int> topKFrequent(vector<int>& nums, int k){
    unordered_map<int, int>frequents;
    for (auto i : nums)    ++frequents[i];//求出每个数的频度
    priority_queue<pair<int, int>>largerK;//first是频度的负数,这样保证top得到的是频度最小的
    auto it = frequents.begin();
    while (it != frequents.end()){
        if (largerK.size() < k)largerK.push({ -(it->second), it->first });//添加前k个元素
        else if(it->second > -(largerK.top().first)){//替换频度最小的
            largerK.pop();
            largerK.push({ -(it->second), it->first });
        }
        ++it;
    }
    vector<int>result;
    while (!largerK.empty()){//将k个数赋给数组
        result.push_back(largerK.top().second);
        largerK.pop();
    }
    return result;
}