C++算法:优先级队列

优先级队列

1.最后一块石头的重量

使用优先级队列模拟即可。

cpp 复制代码
class Solution {
public:
    int lastStoneWeight(vector<int>& stones)
    {
        priority_queue<int> pq;
        for (int& e : stones)
            pq.push(e);
        while (pq.size() > 1)
        {
            int x = pq.top();
            pq.pop();
            int y = pq.top();
            pq.pop();
            if (x > y)
                pq.push(x - y);
        }
        return pq.size() ? pq.top() : 0;
    }
};

2. * TopK:数据流中的第K大元素

这道题其实就是TopK问题。TOP-K问题即求数据集合中前K个或第K大最大的元素或者最小的元素,一般情况下数据量都比较大。如果数据量大,不能使用排序解决,因为可能数据不能一次全部加载到内存,排序算法的空间消耗也会很大。

往往是用堆来解决TopK问题。求第K大的元素,创建小堆,控制堆的大小不超过K,把数据集合的元素入堆。当堆的大小为K时,新元素入堆,此时堆的大小为K+1,堆顶元素是这K+1个元素中最小的,即目前第K+1大的元素,此时pop,堆顶元素就是目前第K大的元素。如此遍历数据集合,就能得到前K个最大元素,堆顶为第K大元素。时间复杂度为O(N*logK)。

cpp 复制代码
class KthLargest {
    priority_queue<int, vector<int>, greater<int>> heap;
    int _k;
public:
    KthLargest(int k, vector<int>& nums)
    {
        _k = k;
        for (int e : nums)
        {
            heap.push(e);
            if (heap.size() > _k)
                heap.pop();
        }
    }

    int add(int val)
    {
        heap.push(val);
        if (heap.size() > _k)
            heap.pop();
        return heap.top();
    }
};

3. * TopK:前K个高频单词

用unordered_map或map统计单词出现频次;创建大小为k的堆,频次不同时满足小根堆,频次相同时,按照字典序,应满足大根堆;得到符合要求的前k个单词后,堆顶元素是频次小,字典序大,所以应该从ret数组尾部开始放元素,否则从头开始放元素后逆置数组。

cpp 复制代码
class Solution
{
    typedef pair<string, int> PSI;
    struct Greater
    {
        bool operator()(const PSI& p1, const PSI& p2)
        {
            if (p1.second == p2.second)
                return p1.first < p2.first;
            return p1.second > p2.second;
        }
    };
public:
    vector<string> topKFrequent(vector<string>& words, int k)
    {
        //统计单词频次
        map<string, int> m;
        for (string& e : words)
            m[e]++;
        
        //TopK
        priority_queue<PSI, vector<PSI>, Greater> heap;
        for (const PSI& psi : m)
        {
            heap.push(psi);
            if (heap.size() > k)
                heap.pop();
        }
        
        //提取结果
        vector<string> ret(k);
        for (int i = k - 1;i >= 0;i--)
        {
            ret[i] = heap.top().first;
            heap.pop();
        }
        return ret;
    }
};

4.数据流的中位数

利用大小堆解决。假设数据有序,数据中位数左边用大根堆left维护,右边用小根堆right维护。

如果m == n,则中位数为(left.top()+right.top())/2;如果m>n,即m == n+1,则中位数为left.top()。

每次add()时,对于新加入的数据num,如果m == n,当m为0或num<=left.top()时,直接进left;当num>left.top()时,num进right,此时m<n,再把right.top()放入left中,保持m == n。

如果m>n,当num>=left.top()时,则num直接进right;当num<left.top()时,num进left,此时m == n+2,再把left.top()放入right中保持 m == n+1。

cpp 复制代码
class MedianFinder
{
    priority_queue<int, vector<int>, less<int>> left;
    priority_queue<int, vector<int>, greater<int>> right;
public:
    MedianFinder()
    {
    }

    void addNum(int num)
    {
        int m = left.size(), n = right.size();

        if (m == n)
        {
            if (m == 0 || num <= left.top())
                left.push(num);
            else
            {
                right.push(num);
                left.push(right.top());
                right.pop();
            }
        }
        else
        {
            if (num < left.top())
            {
                left.push(num);
                right.push(left.top());
                left.pop();
            }
            else
                right.push(num);
        }
    }

    double findMedian()
    {
        int m = left.size(), n = right.size();
        if (m != n)
            return left.top();
        else
            return (left.top() + right.top()) / 2.0;
    }
};
相关推荐
小七在进步1 小时前
数据结构:用队列实现栈
开发语言·数据结构
Turbo正则1 小时前
机器学习入门笔记 | 基础算法及其应用场景
笔记·算法·机器学习
东华万里1 小时前
第37篇 手撕二叉树与堆的底层逻辑
数据结构·算法
知无不研2 小时前
算法:判断一个数是不是2的幂
数据结构·算法
从零开始的代码生活_2 小时前
C++ 模板入门:函数模板、类模板与实例化机制
开发语言·c++·后端
luj_176810 小时前
残熵算法实时化三大瓶颈突破
c语言·开发语言·网络·经验分享·算法
不听话坏10 小时前
Ignition篇(下 一) 动态执行前的事情
开发语言·前端·javascript
mCell10 小时前
你以为短链接只是 Hash + 301/302?
后端·算法·架构
likeyi0710 小时前
require 和 import的区别
开发语言·前端