记录新手小白的做题历程。
题目:
给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。
示例 1:
输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]
思路:这个我最先想到的是哈希表,key用来存整数,而value用来存值,然后用sort来从大到小排序,最后取出前k个就可以数字。
但是sort对哈希表的排序规则我不会写啊qwq。
我在评论区里看到一个 大佬,和我的思路很像,他用哈希表存好数据后,将数据又放入vector,再对value进行排序
我不知道改这么自定义sort的排序,之前没有接触过pair,也不知道该怎么传参。
到网上搜了之后,发现大家都没有直接对哈希表unordered_map排序,而是和这个大佬一样,借用vector<pair<int,int>>
class Solution {
public:
// 升序排序
static int cmp(pair<int, int> a, pair<int, int> b){
return a.second > b.second;
}
vector<int> topKFrequent(vector<int>& nums, int k) {
/*
利用unordered_map + 自定义排序
*/
vector<int> res;
unordered_map<int, int> ht;
for(int n:nums){
ht[n]++;
}
// 转为pair以对value进行排序
vector<pair<int, int>> tmp;
for(auto it = ht.begin(); it!=ht.end(); it++){
tmp.push_back(pair<int, int>(it->first, it->second));
}
sort(tmp.begin(), tmp.end(), cmp);
// 获取答案
for(int i = 0; i < k; i++){
res.push_back(tmp[i].first);
}
return res;
}
};
收获:
1.
不过为什么他的参数里没有加&呢?加了之后也代码也可以实现
2.将哈希表中数据放入vector,tmp.push_back(pair<int,int>(tmp->first,tmp->second));
我是这样写的
3.它这个排序是升序?理解一下
官方代码:
官方的思路与我的差不多(不过应该大家差不多都这么想的吧qwq)
用了最小堆来排序。
class Solution {
public:
static bool cmp(pair<int, int>& m, pair<int, int>& n) {//排序的规则
return m.second > n.second;
}
vector<int> topKFrequent(vector<int>& nums, int k) {
unordered_map<int, int> occurrences;
for (auto& v : nums) {//将所有元素放入哈希表,无序
occurrences[v]++;
}
// pair 的第一个元素代表数组的值,第二个元素代表了该值出现的次数,小项堆
priority_queue<pair<int, int>, vector<pair<int, int>>, decltype(&cmp)> q(cmp);
for (auto& [num, count] : occurrences) {//遍历哈希表中的元素,num是数,后面是出现的次数
if (q.size() == k) {//如果已经装了K个元素
if (q.top().second < count) {//最顶端的数字小于它,将最小项弹出,放入这一个
q.pop();
q.emplace(num, count);
}
} else //未满k个,可以继续装
q.emplace(num, count);
}
}
vector<int> ret;
while (!q.empty()) {//放入答案
ret.emplace_back(q.top().first);
q.pop();
}
return ret;
}
};
思路:1.统计元素出现次数并放入哈希表
2,创建最小堆(只有最小堆才能剔除小值保留大值)
3,遍历哈希表,依次放入元素,若最小堆中的size未超过K,可以直接放入数据,若多于k,则需要将堆顶与新值进行比较,若新值大,则需要弹出堆顶,插入新值。
4,最后创建答案数组,将最大堆的元素放入数组内。
收获:
1. priority_queue<pair<int, int>, vector<pair<int, int>>, decltype(&cmp)> q(cmp);
//设了一个最大堆用来排序,改变三个参数,第一个是存储的数据类型,第二个是容器类型,第三个是比较方式,重新创建的规则
2. 没有见过decltype,了解一下。emmm,为什么最后面是q(cmp)啊,搞不懂搞不懂。理解不了就死记。 创建堆时的cmp不能去掉,否则会报错。
3.是pair,不是pairs
4.comp前面一定要有static,其函数需要对元素排序,所以参数需要加&,comp内的参数如何写要记住
5.auto无法遍历堆,像这样写for(auto& [num,count]:q)是错误的,但vector可以,
for(auto& [num,count]:occurrences)没错,所以代码最后是用堆是否为空来决定是否进行循环,而不是遍历q
方法二:快速排序
class Solution {
public:
void qsort(vector<pair<int, int>>& v, int start, int end, vector<int>& ret, int k) {
int picked = rand() % (end - start + 1) + start;
swap(v[picked], v[start]);
int pivot = v[start].second;
int index = start;
for (int i = start + 1; i <= end; i++) {
if (v[i].second >= pivot) {
swap(v[index + 1], v[i]);
index++;
}
}
swap(v[start], v[index]);
if (k <= index - start) {
qsort(v, start, index - 1, ret, k);
} else {
for (int i = start; i <= index; i++) {
ret.push_back(v[i].first);
}
if (k > index - start + 1) {
qsort(v, index + 1, end, ret, k - (index - start + 1));
}
}
}
vector<int> topKFrequent(vector<int>& nums, int k) {
unordered_map<int, int> occurrences;
for (auto& v: nums) {
occurrences[v]++;
}
vector<pair<int, int>> values;
for (auto& kv: occurrences) {
values.push_back(kv);
}
vector<int> ret;
qsort(values, 0, values.size() - 1, ret, k);
return ret;
}
};
我的天哪,这道题肝了我几个小时,还有快速排序方法实在是懒得看了······
记在这里,下次一定。