你能比O(nlogn)更好地做Top-K频繁元素吗? (已附加代码)

时间:2016-05-14 11:58:44

标签: c++ algorithm

最近遇到一个算法问题,要求比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;

    }

提前感谢您的回复。

0 个答案:

没有答案