要求:返回前k个高频元素,时间不超O(nlogn),注意是指k个不同的数而不是k个频率
思路:
法一:首先记录次数数组,由于时间限制不能排序,故对该数组用小顶堆,初始化堆O(klogk),调整O(n-k)(logk),空间O(n)
class Solution {
public:
struct cmp{
bool operator()(pair<int,int> &a,pair<int,int> &b){
return a.second>b.second;
}
};
vector<int> topKFrequent(vector<int>& nums, int k) {
unordered_map<int,int> times;
int n=nums.size();
for(int i=0;i<n;i++)
times[nums[i]]++;
priority_queue<pair<int,int>,vector<pair<int,int>>,cmp> minheap;
int num=0;
for(auto a:times){
if(num<k){
minheap.push(a);
num++;
}
else if(a.second>minheap.top().second){
minheap.pop();
minheap.push(a);
}
}
vector<int> res;
while(!minheap.empty()){
res.push_back(minheap.top().first);
minheap.pop();
}
return res;
}
};
法二:快排的partition函数找次数数组里第n-k个,随便写写,时间在O(n)~O(n^2),空间O(n)
class Solution {
public:
vector<int> topKFrequent(vector<int>& nums, int k) {
unordered_map<int,int> hash;
int n=nums.size();
for(int i=0;i<n;i++)
hash[nums[i]]++;
vector<int> times;
for(pair<int,int> a:hash)
times.push_back(a.second);
n=times.size();
k=n-k;
int l=0,r=n-1;
int num=0;
while(true){
num=partition(times,l,r);
if(num==k)break;
else if(num<k)l=num+1;
else r=num-1;
}
cout<<num;
vector<int> res;
for(pair<int,int> a:hash)
if(a.second>=times[num])
res.push_back(a.first);
return res;
}
int partition(vector<int> ×,int l,int r){
int i=l,j=r;
int pivot=times[l];
while(i<j){
while(i<j&×[j]>=pivot)
j--;
times[i]=times[j];
while(i<j&×[i]<=pivot)
i++;
times[j]=times[i];
}
times[i]=pivot;
return i;
}
};
法三:桶排序,空间换时间,每个频率一个vector,注意一下vector下表,时间O(n),空间O(n)
class Solution {
public:
vector<int> topKFrequent(vector<int>& nums, int k) {
unordered_map<int,int> times;
for(auto a:nums)
times[a]++;
int maxfreq=0;
for(auto a:times)
maxfreq=max(maxfreq,a.second);
vector<vector<int>> buckets(maxfreq);
for(auto a:times)
buckets[a.second-1].push_back(a.first);
vector<int> res;
int num=0;
for(int i=maxfreq-1;num<k&&i>=0;i--){
if(buckets[i].empty())continue;
for(auto a:buckets[i]){
res.push_back(a);
num++;
}
}
return res;
}
};