LeetCode 347. Top K Frequent Elements 解题报告
来源:互联网 发布:优惠券制作软件 编辑:程序博客网 时间:2024/06/09 18:37
LeetCode 347. Top K Frequent Elements 解题报告
题目描述
Given a non-empty array of integers, return the k most frequent elements.
示例
Given [1,1,1,2,2,3] and k = 2, return [1,2].
注意事项
- 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.将原来的数组进行排序
2.遍历数组,遍历过程中记下每个数字出现的次数,将(数字,出现次数)这一组信息保存在一个vector里
3.按照出现次数由多至少对vector的元素进行排序
4.保存vector的前k个元素到存储结果的数组中,返回存储结果的数组。
通过了肯定得看看其他人是怎么做的,好吧,看完了真心感觉自己在算法上有很大的缺陷,大牛们用到了不同的算法跟数据结构去完成这道题,下面我一个个来实现一次。
参考思路:
桶排序
桶排序算法大概的过程是将数据分到不同的桶中,这些桶都是有序,然后对桶内的元素排序,最后从第一个桶开始把所有元素串起来就是一个有序的数列,见下面wiki中的图:
那桶排序算法是怎样用在这道题里的呢?答案是利用了桶之间有序的特性。
- 首先用一个unordered_map存储数组中每个元素及其出现的次数。
- 然后构建桶结构,(其实就是vector组成的二维数组),桶的序号设为出现次数,即1号桶表示出现1次,2号桶表示出现2次,依次类推(这就是为什么代码里构建桶时是unordered_map长度+1的原因,0号桶不用,最多次数为unordered _map的长度)
- 然后根据数字出现次数把它们放到相应的桶内,完成这一步之后各个数字就已经是有序了。
- 最后从最后一个桶开始(因为最后一个桶表示出现次数最多),倒序地把各个桶内的数字放入到结果数组中,直到结果数组刚好有k个元素。
实现见参考代码1,代码很直观易懂。
堆结构
这道题还可以用堆这个数据结构来完成,基本思想是利用了堆以一定的偏序保存节点的特性,下面讲述利用最大堆和最小堆的实现。
两个实现第一步都是用unordered_map保存数字及其出现的次数。
最大堆:堆中保存的是次数最大的k个数字。不断地向堆放入数据,当堆中元素超过k时就弹出数据,此时被弹的数据是堆中出现次数最小的数字。最后将堆中剩下的元素返回。实现中使用了vector以及make_heap,pop_heap函数。见参考代码2。
最小堆:堆中保存的是次数最小的n-k个数字,n为unordered_map的大小。不断地向堆放入数据,当堆中元素超过n-k时就弹出数据,此时被弹的数据是堆中出现次数最大的数字,因为n-k个次数小的在堆中,所以被弹出的就是k个最大的元素,保存被弹出的数据。最后这些数据返回。实现中使用了优先队列priority_queue作为堆结构,见参考代码3。
代码
我的代码
class Solution {public: vector<int> topKFrequent(vector<int>& nums, int k) { vector<pair<int, int> > freq; vector<int> kFrequent; sort(nums.begin(), nums.end()); nums.push_back(nums[nums.size() - 1]); for (int i = 0, j = 1, count = 0; j < nums.size();) { if (nums[i] != nums[j] || j == nums.size() - 1) { count = j - i; freq.push_back(pair<int, int>(nums[i], count)); i = j; j++; } else { j++; } } sort(freq.begin(), freq.end(), [](pair<int, int>a, pair<int, int>b) { return a.second > b.second; }); for (int i = 0; i < k; i++) { kFrequent.push_back(freq[i].first); } return kFrequent; }};
参考代码1:桶排序
class Solution {public: vector<int> topKFrequent(vector<int>& nums, int k) { unordered_map<int, int> htable; for (auto n: nums) htable[n]++; vector<vector<int>> bucket(nums.size() + 1); for (auto h: htable) bucket[h.second].push_back(h.first); vector<int> ans; for (int i = bucket.size() - 1; i>=0 && ans.size() < k; i--) { for (int j = 0; j < bucket[i].size(); j++) { ans.push_back(bucket[i][j]); if (ans.size() == k) break; } } return ans; }};
参考代码2:最大堆
class Solution {public: vector<int> topKFrequent(vector<int>& nums, int k) { unordered_map<int, int> htable; for (auto n: nums) htable[n]++; vector<pair<int, int>> heap; for (auto h: htable) heap.push_back({h.second, h.first}); make_heap(heap.begin(), heap.end()); vector<int> ans; while(k--) { ans.push_back(heap.front().second); pop_heap(heap.begin(), heap.end()); heap.pop_back(); } return ans; }};
参考代码3:最小堆
class Solution {public: vector<int> topKFrequent(vector<int>& nums, int k) { unordered_map<int, int> htable; for (auto n: nums) htable[n]++; // pair(frequency, number) priority_queue<pair<int, int>> heap; vector<int> ans; for (auto p: htable) { heap.push({p.second, p.first}); if (heap.size() > htable.size() - k) { ans.push_back(heap.top().second); heap.pop(); } } return ans; }};
总结
这道题让我学了很多知识,复习了桶排序,堆数据结构,以及STL中一些函数和容器的使用,多做题真的是能学到东西。做题关键的还是要灵活运用自己学过的算法和数据结构,以后自己要多加注意。
填坑真快乐~继续加油!
- [leetcode] 347. Top K Frequent Elements 解题报告
- leetcode 347. Top K Frequent Elements 解题报告
- LeetCode 347. Top K Frequent Elements 解题报告
- [Leetcode] 347. Top K Frequent Elements 解题报告
- Leetcode #347. Top K Frequent Elements 前K高频数 解题报告
- Top K Frequent Elements解题报告
- LeetCode---Top K Frequent Elements解题分析
- LeetCode #347. Top K Frequent Elements
- [leetcode] 347. Top K Frequent Elements
- LeetCode 347. Top K Frequent Elements
- <LeetCode OJ> 347. Top K Frequent Elements
- LeetCode 347. Top K Frequent Elements
- Leetcode 347. Top K Frequent Elements
- LeetCode Everyday: 347. Top K Frequent Elements
- 【leetcode】347. Top K Frequent Elements
- leetcode 347.Top K Frequent Elements
- leetcode 347. Top K Frequent Elements
- leetcode 347. Top K Frequent Elements
- Android 观察者模式
- 写wal log日志
- 2016秋季练习
- html-css
- 事件分发机制(一)
- LeetCode 347. Top K Frequent Elements 解题报告
- 使用制作UGUI的UI流程管理机制
- android vlc 编译后添加 android studio
- Git 一键生成补丁 old folder new folder update.path
- Java对象和类
- vs1003b中的寄存器
- 一周的总结
- 算法分析(一)堆排序原理及java实现
- (java)整数数组中求最大连续子序列之和,并且记录开始和结束位置