最近遇到一个算法问题,要求比O(nlogn)更好地做Top-K频繁元素。我使用C ++实现它并进行了一些复杂性分析。我觉得不可能比O(nlogn)做得更好。附上我的代码和复杂性分析。我用地图。我认为unordered_map在实践中会做得更好但是,对于最坏情况分析,由于哈希冲突,unordered_map比map差。在最坏的情况下,它会使第一个块成为O(n ^ 2)。
描述: 给定一个非空的整数数组,返回k个最常用的元素。 例如, 给定[1,1,1,2,2,3]和k = 2,返回[1,2]。 注意: 您可以假设k始终有效,1≤k≤唯一元素的数量。 您的算法的时间复杂度必须优于O(n log n),其中n是数组的大小。
谷歌搜索的许多解决方案都使用哈希表,而那些假设对哈希表插入操作的解决方案是O(1),在我看来,这不是真的。因为在最坏的情况下,当哈希冲突发生时,哈希表产生O(n ^ 2)用于插入操作。 Big O表示法是关于最坏情况分析的。
vector<int> topKFrequent(vector<int>& nums, int k) {
map<int, int> _map;
vector<int> result;
//complexity: O(nlogn)
for(auto n : nums) {
// map.find() has O(logn)
if (_map.find(n) != _map.end()) {
// have seen before
_map[n]++;
} else {
// new one,
_map[n]=1;
}
}
//complexity: O(n)
vector<pair<int,int>> v;
for(auto itr = _map.begin(); itr != _map.end(); ++itr) {
v.push_back(make_pair(itr->first, itr->second));
}
// complexity: O(n) (build a heap)
auto f = [] (pair<int,int> p1, pair<int,int> p2) { return p1.second < p2.second; };
make_heap(v.begin(), v.end(), f);
// complexity: O(k*logn)
while(k) {
result.push_back(v.front().first);
pop_heap(v.begin(), v.end(),f); // delete heap from binary tree O(logn)
// 1. swap root with last leaf O(1)
// 2. find right place for last leaf
v.pop_back();
k--;
}
return result;
}
提前感谢您的回复。