leetcode hot100 堆

如有缺漏谬误,还请批评指正。

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;
    }
};

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值