LintCode 1281: Top K Frequent Elements (堆经典题)

  1. Top K Frequent Elements
    中文English
    Given a non-empty array of integers, return the k most frequent elements.

Example
Example 1:

Input: nums = [1,1,1,2,2,3], k = 2
Output: [1,2]
Example 2:

Input: nums = [1], k = 1
Output: [1]
Notice
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.

解法1:用最大堆。prority_queue<>缺省就是最大堆。时间复杂度MlogM,其中M是不重复数据的数目。
注意:
1)unordered_map 不能用for (int i = 0; i < um.size(); ++i),因为它是unordered。但可以用auto 。


class Solution {
public:
    /**
     * @param nums: the given array
     * @param k: the given k
     * @return: the k most frequent elements
     */
    vector<int> topKFrequent(vector<int> &nums, int k) {
        unordered_map<int, int> um;  //num, freq
        priority_queue<pair<int, int>> pq;
        vector<int> result;
        
        for (int i = 0; i < nums.size(); ++i) um[nums[i]]++;
        
        //for (int i = 0; i < um.size(); ++i) {
        //    pq.push({um[i].second, um[i].first});
        //}
        for (auto m : um) {
            pq.push({m.second, m.first});
        }
        
        for (int i = 0; i < k; ++i) {
            result.push_back(pq.top().second);
            pq.pop();
        }
     
        return result;   
    }
};

解法2:最小堆。时间复杂度MlogK。
代码如下:


struct ResultType {
    int val;
    int freq;
    ResultType(int v = 0, int f = 0) : val(v), freq(f) {}
};

struct cmp {
    bool operator() (const ResultType & a, const ResultType & b) {
        if (a.freq > b.freq) {
            return true;
        } else if (a.freq == b.freq && a.val > b.val) {
            return true;
        } else {
            return false;
        }
    }
};

class Solution {
public:
    /**
     * @param nums: the given array
     * @param k: the given k
     * @return: the k most frequent elements
     */
    vector<int> topKFrequent(vector<int> &nums, int k) {
        unordered_map<int, int> um; //num, freq
        vector<int> result;
        priority_queue<ResultType, vector<ResultType>, cmp> pq;
        
        for (int i = 0; i < nums.size(); ++i) {
            um[nums[i]]++;
        }
        
        int count = 0;
        for (auto it : um) {
            pq.push(ResultType(it.first, it.second));
            if (count++ >= k) pq.pop();
        }
        
        while(!pq.empty()) {
            result.push_back(pq.top().val);
            pq.pop();
        }
        
        return result;
    }
};

解法3:还是最小堆。用一个map<int,int> freqs和Node结构,里面包含了num和重载了operator<,这个operator<就是根据freqs来排序,注意是最小堆,所以是freqs[num] > freqs[node.num]。

map<int, int> freqs; //<int, freq>
struct Node {
    int num;
    Node(int n) : num(n) {}
    bool operator < (const Node & node) const {
        return freqs[num] > freqs[node.num];
    }
};

class Solution {
public:
    vector<int> topKFrequent(vector<int>& nums, int k) {
        int len = nums.size();
        priority_queue<Node> minHeap;
        freqs.clear();
        
        for (int i = 0; i < len; i++) {
            freqs[nums[i]]++;
        }
        
        for (auto f : freqs) {
            if (minHeap.size() < k) {
                minHeap.push(Node(f.first));
            } else {
                //注意minHeap里面已经包含了到现在为止k个most frequent的数字,minHeap.top就是到现在为止第kth most frequent的那个数字,如果当前数字的frequency比minHeap.top还小就没有必要push进去了。注意最开始的第一个for循环已经得到了每个数字在整个数组中的frequency。这个优化很重要。
                if (f.second > freqs[minHeap.top().num]) {
                    minHeap.push(Node(f.first));
                    minHeap.pop();
                }
            }
        }

        vector<int> res;
        while (!minHeap.empty()) {
            res.push_back(minHeap.top().num);
            minHeap.pop();
        }
        return res;
    }
};

解法4:跟上面差不多,只是用了decltype的表示法。

class Solution {
public:
    vector<int> topKFrequent(vector<int>& nums, int k) {
        vector<int> res;
        map<int, int> freqs; //<num, freq>
        int n = nums.size();
        for (int i = 0; i < n; i++) {
            freqs[nums[i]]++;
        }
        auto comp = [&](int a, int b){return freqs[a] > freqs[b];};
        priority_queue<int, vector<int>, decltype(comp)> minHeap(comp);
        
        for (auto f : freqs) {
            minHeap.push(f.first);
            if (minHeap.size() > k) {
                minHeap.pop();
            }
        }
        while(k--) {
            res.push_back(minHeap.top());
            minHeap.pop();
        }
        reverse(res.begin(), res.end());
        return res;
    } 
};

另一个用minHeap的方法,直接用pair<int, int>,注意是反着用的,freq是first, num是second,这样就可以利用freq来排序,如果freq相同则利用字母顺序来排序,不需要重新定义Node。

class Solution {
public:
    vector<int> topKFrequent(vector<int>& nums, int k) {
        int n = nums.size();
        priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int,int>>> minHeap; // <freq, number>
        vector<int> res;
        unordered_map<int, int> num2Freq;
        for (auto n : nums) num2Freq[n]++;
        int index = 0;
        for (auto elem : num2Freq) {
            index++;
            minHeap.push({elem.second, elem.first});
            if (index > k) minHeap.pop();
        }
        while(!minHeap.empty()) {
            auto node = minHeap.top();
            minHeap.pop();
            res.push_back(node.second);
        }
        reverse(res.begin(), res.end());
        return res;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值