day13 | 队列应用(单调队列、优先级队列)

149 阅读2分钟

239. 滑动窗口最大值

题目链接:leetcode.cn/problems/sl…

要点

  • 需要的队列主要实现三个方法:pop(val), push(val), get_max()
  • 优先级队列 每次pop后会重新调整堆,使得最大值在出口位置;不适用与本题因为由于FIFO的特性在维护滑动窗口时,窗口的pop操作受阻
  • 维护队列未必要把所有窗内元素保持在队内,因此实现一个单调队列

  • lower_queue中 1. 元素的先后顺序同数组顺序 2. 单调递减
  • 实现push()时,为了保证单调性,将所有比插入数小的元素pop出,他们不可能作为某个窗口max输出

单调队列

class Solution {
private:
    class lower_queue{
        deque<int> dq;
    public:
        void pop(int val) {
            if (!dq.empty() && val == dq.front()) {
                dq.pop_front();
            }
        }

        void push(int val) {
            while (!dq.empty() && dq.back() < val) {
                dq.pop_back();
            }
            dq.push_back(val);
        }

        int get_max() {
            return dq.front();
        }
    };

public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        lower_queue que;
        vector<int> res;
       
        for (int i = 0; i < k; ++i) {
            que.push(nums[i]);
        }
        res.push_back(que.get_max());
        for (int j = k; j < nums.size(); ++j) {
            que.pop(nums[j-k]);
            que.push(nums[j]);
            res.push_back(que.get_max());
        }
        return res;
    }
};

总结

时间复杂度为O(n),空间复杂度为O(k)

347. 前 K 个高频元素

题目链接:leetcode.cn/problems/to…

要点

  • 优先级队列初始化:priority_queue< type, container, function >
  • 仿函数greater, less都是结构体,体内重载()来模拟函数操作。两者都在头文件functionalblog.csdn.net/jay_zzs/art…
  • 优先级队列(堆)中的cmp函数与通常排序的cmp函数大小比较相反

  • 优先级队列取首元素为top(), 不是front()
  • for (auto it : map) it是pair元素,不是迭代器

优先级队列

class Solution {
public:
    //实现一个比较的仿函数,小顶堆
    struct cmp{
        bool operator() (const pair<int, int>& lp, const pair<int, int>& rp){
            return lp.second > rp.second;
        }
    };

    vector<int> topKFrequent(vector<int>& nums, int k) {
        unordered_map<int, int> map;
        for (int i = 0; i < nums.size(); i++) map[nums[i]]++;

        priority_queue<pair<int, int>, vector<pair<int, int>>, cmp> que;
        for (auto it : map) {
            que.push(it);                             //bug! 不用解引用
            if (que.size() > k) que.pop();
        }

        vector<int> res(k);
        for (int i = k-1; i >= 0; i--) {
            res[i] = que.top().first;
            que.pop();
        }
        
        return res;
    }
};

总结

堆的更新时间复杂度为O(logn),建堆为O(n),此题的时间复杂度为O(nlogk)