如有缺漏谬误,还请批评指正。
1.第k大的元素
(1)建堆:从最后一个非叶子结点开始建大根堆,建堆时递归调整。
核心操作:如果某个孩子比当前节点大,则交换它们,并递归建堆操作(因为此时被交换的结点可能不满足大根堆的性质)。
(2)找第k大的元素:从堆尾元素开始一个个弹出并调整堆,弹出k-1次后,堆顶元素就是第k大的元素。
class Solution {
public:
void maxHeapify(vector<int>& a,int i,int heapSize){
int l=i*2+1,r=i*2+2,largest=i;
if(l<heapSize&&a[l]>a[largest]) largest=l;
if(r<heapSize&&a[r]>a[largest]) largest=r;
if(largest!=i){
swap(a[i],a[largest]);
maxHeapify(a,largest,heapSize);
}
}
void buildMax(vector<int>& nums,int heapSize){
for(int i=heapSize/2-1;i>=0;i--){
maxHeapify(nums,i,heapSize);
}
}
int findKthLargest(vector<int>& nums, int k) {
int heapSize=nums.size();
buildMax(nums,heapSize);
for(int i=nums.size()-1;i>=nums.size()-k+1;i--){
swap(nums[0],nums[i]);
heapSize--;
maxHeapify(nums,0,heapSize);
}
return nums[0];
}
};
2.前k个高频元素
(1)堆里已有k个元素:比较当前元素和堆顶元素(堆中元素的最小值),若当前元素大于堆顶元素,则弹出堆顶元素,并把当前元素放入堆中。
(2)堆里元素还不满k个:直接把当前元素放入堆中。
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]++;
priority_queue<pair<int,int>,vector<pair<int,int>>,decltype(&cmp)> q(cmp);
for(auto &[num,cnt]:occurrences){
if(q.size()==k){
if(q.top().second<cnt){
q.pop();
q.push({num,cnt});
}
}
else q.push({num,cnt});
}
vector<int> res;
while(q.size()){
res.push_back(q.top().first);
q.pop();
}
return res;
}
};
3.数据流的中位数
使用两个堆(优先队列)来维护数据:
-
queMin:最大堆(使用
less<int>
比较器),存储数据流中较小的一半数字 -
queMax:最小堆(使用
greater<int>
比较器),存储数据流中较大的一半数字
算法流程:
(1)判断新数字应加入哪个堆
①如果queMin为空,或num<=queMin的堆顶(小于等于较小一半数字的最大值),则加入queMin
②否则加入queMax
(2)平衡两个堆的大小
①如果加入queMin后queMin的大小比queMax大2个以上,则将queMin的堆顶移到queMax
②如果加入queMax后queMax的大小比queMin大,则将queMax的堆顶移到queMin
结果输出:
(1)如果 queMin 的大小 > queMax 的大小(总数为奇数):中位数就是 queMin 的堆顶
(2)否则(总数为偶数):中位数是 queMin 堆顶和 queMax 堆顶的平均值
class MedianFinder {
public:
priority_queue<int,vector<int>,less<int>> queMin;
priority_queue<int,vector<int>,greater<int>> queMax;
MedianFinder(){}
void addNum(int num){
if (queMin.empty()||num<=queMin.top()) {
queMin.push(num);
if (queMax.size()+1<queMin.size()) {
queMax.push(queMin.top());
queMin.pop();
}
}
else{
queMax.push(num);
if (queMax.size()>queMin.size()) {
queMin.push(queMax.top());
queMax.pop();
}
}
}
double findMedian() {
if(queMin.size()>queMax.size()) return queMin.top();
return (queMin.top()+queMax.top())/2.0;
}
};