桶排序:leetcode347(20230111)
给你一个整数数组 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 是数组大小。
Related Topics
数组
哈希表
分治
桶排序
计数
快速选择
排序
堆(优先队列)
解法1:使用两次桶排序
桶排序一般是O(n),符合题目要求小于O(nlogn)
#include<bits/stdc++.h>
using namespace std;
//leetcode submit region begin(Prohibit modification and deletion)
class Solution {
public:
vector<int> topKFrequent(vector<int>& nums, int k) {
//两遍桶排序
map<int, int> counts;
int max_count = 0;
for (const int & num : nums) {
max_count = max(max_count, ++counts[num]);
}
vector<vector<int> > buckets(max_count + 1);
map<int,int>::iterator it;
for (it=counts.begin();it!=counts.end();it++) {
buckets[it->second].push_back(it->first);
}
vector<int> ans;
for (int i = max_count; i >= 0 && ans.size() < k; --i) {
for (const int & num : buckets[i]) {
ans.push_back(num);
if (ans.size() == k) {
break;
}
}
}
return ans;
}
};
总结:
使用stl map来解决桶排序中空间浪费严重的问题
使用多遍桶排序将时间复杂度降低到O(nlogn)之下
学习map的遍历方法
解法2:使用堆(优先队列),建议使用c语言
维护一个大小为k的小顶堆,每次新元素进来就更新小顶堆
class Solution {
public:
vector<int> topKFrequent(vector<int>& nums, int k) {
unordered_map<int, int> freq; // 统计词频
for (auto& num : nums) ++freq[num];
// 比较器
auto pred = [](const auto& p1, const auto& p2)->bool {
return p1.second > p2.second;
};
priority_queue<pair<int, int>, vector<pair<int, int>>, decltype(pred)> pq(pred);
// 维护前k高的数字
for (auto& p : freq) {
pq.emplace(p);
if (pq.size() > k) pq.pop();
}
vector<int> ans;
while (!pq.empty()) { // 加入答案 并返回
ans.emplace_back(pq.top().first);
pq.pop();
}
return ans;
}
};
总结:
复习stl优先队列的使用
要慎用stl,夏令营考试一般使用纯c
桶排序:leetcode451(20230112)
给定一个字符串 s ,根据字符出现的 频率 对其进行 降序排序 。一个字符出现的 频率 是它出现在字符串中的次数。
返回 已排序的字符串 。如果有多个答案,返回其中任何一个。
示例 1:
输入: s = "tree"
输出: "eert"
解释: 'e'出现两次,'r'和't'都只出现一次。
因此'e'必须出现在'r'和't'之前。此外,"eetr"也是一个有效的答案。
示例 2:
输入: s = "cccaaa"
输出: "cccaaa"
解释: 'c'和'a'都出现三次。此外,"aaaccc"也是有效的答案。
注意"cacaca"是不正确的,因为相同的字母必须放在一起。
示例 3:
输入: s = "Aabb"
输出: "bbAa"
解释: 此外,"bbaA"也是一个有效的答案,但"Aabb"是不正确的。
注意'A'和'a'被认为是两种不同的字符。
提示:
1 <= s.length <= 5 * 105
s 由大小写英文字母和数字组成
Related Topics
哈希表
字符串
桶排序
计数
排序
堆(优先队列)
方法一:两遍桶排序
class Solution {
public:
char ans[500000];
string frequencySort(string s) {
vector<int> freq(128,0);
int index=0;
int max=0;
for(int i=0;i<s.size();i++){
int index=s[i];
freq[index]++;
}
for(int i=0;i<128;i++){
max= std::max(max,freq[i]);
}
vector<vector<int>> bucket(max+1);
for(int i=0;i<128;i++){
bucket[freq[i]].push_back(i);
}
for(int i=max;i>=0;i--){
if(bucket[i].empty()){
continue;
}
for(int j=0;j<bucket[i].size();j++){
for(int k=0;k<i;k++){
char ch=bucket[i][j];
ans[index++]='\0'+bucket[i][j];
}
}
}
ans[index]='\0';
string str=ans;
return str;
}
};
方法二:优先队列,更快
要注意优先队列的用法,以及pair比较时候默认比较第一个元素
class Solution {
public:
char ans[500000];
string frequencySort(string s) {
priority_queue<pair<int,int>,vector<pair<int,int>>,less<pair<int,int> > > dict;
vector<int> freq(128,0);
int index=0;
for(int i=0;i<s.size();i++){
int idx=s[i];
freq[idx]++;
}
for(int i=0;i<freq.size();i++){
dict.push(make_pair(freq[i],i));
}
while (!dict.empty()){
pair<int,int> tmp=dict.top();
dict.pop();
for(int i=0;i<tmp.first;i++){
ans[index++]=tmp.second;
}
}
ans[index]='\0';
string str=ans;
return str;
}
};