347,23

典型可以使用优先队列的。

(小顶堆)

 

class Solution {
public:
    vector<int> topKFrequent(vector<int>& nums, int k) {
        
        assert(k>0);
        
        //统计每个元素出现的频率
        unordered_map<int,int> freq;   //freq<元素,频率>
        for(int i=0; i<nums.size();i++){
            freq[nums[i]] ++;  
        }
        
        assert(k<=freq.size());
        
        //扫描freq,维护当前出现频率最高的k个元素
        //在优先队列中,按照频率排序,所以数据对是(频率,元素)的形式.因为在pair中比较时,先比较的是频率
        priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>> > pq;  //优先队列,从小到大排序
        
        for(unordered_map<int, int>::iterator iter = freq.begin(); iter!=freq.end(); iter++){
            
            //当前的优先队列已经维护了k个出现频率最高的元素
            if(pq.size() == k){
                if(iter->second > pq.top().first){ //iter<元素,频率>
                    pq.pop();   //将更小频率的元素扔掉
                    pq.push(make_pair(iter->second, iter->first));
                }
            }
            else
                pq.push(make_pair(iter->second, iter->first));
        }
        
        vector<int> res;
        while(!pq.empty()){
            res.push_back(pq.top().second);
            pq.pop();
        }
        return res;
    }
};

 


 但是若k和n差不多大,方法二就比较耗时了。则方法三的优势就很明显了。

 

typedef pair<int, int> PAIR; 
class Solution {
public:
    
    static int cmp(PAIR &a, PAIR &b){
        
        return a.second>b.second;
    }
    
    vector<int> topKFrequent(vector<int>& nums, int k) {
        
        vector<int> v;
        map<int, int> m;
        vector<PAIR> pair_vec;
        for(int i=0;i<nums.size();++i){
            
            m[nums[i]]++;
        }
        for(map<int,int>:: iterator it = m.begin(); it!=m.end(); ++it){
            
            pair_vec.push_back(make_pair(it->first, it->second));
        }
        sort(pair_vec.begin(), pair_vec.end(),cmp);
        vector<PAIR>::iterator it = pair_vec.begin();
        while(k--){
            
            v.push_back(it->first);
            ++it;
        }
        
        return v;
    }
    
};

 

 

 

合并前的k个链表是有序的,最终合并后的链表也是有序的

 使用优先队列(小顶堆),先将K个链表的首元素都加入最小堆中,然后每次取出最小的那个元素加入到最终的链表中。然后把取出元素的下一个元素再加入堆中,下次仍从堆中取出最小的元素做相同的操作。以此类推,直到堆中没有元素了。此时返回合成链表的首结点。

 这里注意两点:

1)比较函数的写法;

2)由于优先队列默认是大顶堆,它重载了< ,优先队列会认为 a < b ,即 b 的优先级比 a 高,所以 b会被先出队,假设 a->val > b->val 为 TRUE,这样就实现了关键字小的元素先出队。它和sort比较函数的写法是相反的。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    
    struct cmp{
        bool operator()(ListNode* a, ListNode* b){
            return a->val > b->val;
        } 
    };
    
    ListNode* mergeKLists(vector<ListNode*>& lists) {
        priority_queue<ListNode*, vector<ListNode*>,cmp> q;
        
        //将k个链表的首结点推入优先队列中
        for(int i=0;i<lists.size();i++)
            if(lists[i])
                q.push(lists[i]);
        
        ListNode* dummy = new ListNode(-1), *cur = dummy, *t = NULL;
        while(!q.empty()){
            t = q.top();
            q.pop();
            cur->next = t;
            cur = cur->next;
            if(cur->next)
                q.push(cur->next);
        }
        return dummy->next;
    }
};

 

posted @ 2019-02-23 11:14  爱学英语的程序媛  阅读(175)  评论(0编辑  收藏  举报