题目
题目链接:力扣 347. 前 K 个高频元素
给你一个整数数组 nums
和一个整数 k
,请你返回其中出现频率前 k
高的元素。你可以按 任意顺序 返回答案。
示例 1:
输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]
示例 2:
输入: nums = [1], k = 1
输出: [1]
提示:
- 1 <= nums.length <= 105
k
的取值范围是[1, 数组中不相同的元素的个数]
- 题目数据保证答案唯一,换句话说,数组中前
k
个高频元素的集合是唯一的
进阶:你所设计算法的时间复杂度 必须 优于 O(n log n)
,其中 n
是数组大小。
解题思路
👉哈希表排序
这种思路和 昨天的那题 的第一种思路一样
就是把每种数字的频次存入一个哈希表中,然后对哈希表据频次进行排序,再取哈希表中前 k
个数字放入数组中返回。具体的排序做法和昨天的每日一题一样,今天就不多说了,后面取前 k
个数字也非常简单不会的可以直接看代码。
👉桶排序
其实桶排序和昨天的题思路也非常一致
把数字的频次存入哈希表中,同时取出最大的频次值。再用一个二维数组把哈希表中的频次(值)当作数组的下标,哈希表的数字(键)作为数组的值。然后就可以逆向遍历二维数组,因为此时的二维数组的下标就是频次值,取前 k
个就行了。
由于会存在同一种频次的多种数字,所以需要用二维数组存储。同时也由于这个原因,需要在取 k
个值时,判断是否取到了 k
,防止超过。
代码(C++)
哈希表排序
class Solution {
public:
unordered_map<int, int> map;
static bool cmp(pair<int, int> a, pair<int, int> b) {
return a.second > b.second;
}
vector<int> topKFrequent(vector<int>& nums, int k) {
for (int i = 0; i < nums.size(); i ++ ) {
map[nums[i]] ++;
}
unordered_map<int, int>::iterator iter;
vector<pair<int, int>> vec;
for (iter = map.begin(); iter != map.end(); iter ++ ) {
vec.push_back(make_pair(iter->first, iter->second));
}
vector<int> num;
sort(vec.begin(), vec.end(), cmp);
for (int i = 0; i < k; i ++ ) {
num.push_back(vec[i].first);
}
return num;
}
};
桶排序
class Solution {
public:
unordered_map<int, int> map;
vector<int> topKFrequent(vector<int>& nums, int k) {
int m = 0;
for (int i = 0; i < nums.size(); i ++ ) {
m = max(m, ++ map[nums[i]]);
}
vector<vector<int>> vec(m + 1);
unordered_map<int, int>::iterator iter;
for (iter = map.begin(); iter != map.end(); iter ++ ) {
vec[iter->second].push_back(iter->first);
}
vector<int> ber;
for (int i = m; i >= 0 && ber.size() < k; i -- ) {
for (int j = 0; j < vec[i].size(); j ++ ) {
ber.push_back(vec[i][j]);
if (ber.size() == k)
break;
}
}
return ber;
}
};
总结
今天的题和昨天的高度重合,为什么我还是要选择这题讲解呢?因为今天上了一天的课,后天还有一场比赛,所以就想水一篇😝(虽然前面的也挺水,但我真的认真写了)。这题官方给的题解有小根堆和快排解法,但我不想再看了,如果后面能想起来再更新这两种解法吧。