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; } };