day13 栈与队列part03

239. 滑动窗口最大值

如何想到用队列这个数据结构我觉得得看经验,这个题目是经典的单调队列的问题,设想我们有一个队列来依次装进入队列的元素,我们要求的是最大值,那么如果后面来了一个大值,前面的小值一定不会作为答案输出,因为后面那个大值在窗口存活的时间更久并且前面的小值更早被弹出,所以这个小值是不可能作为窗口的最大值输出的,所以这个小值不需要被遍历,从而减少了判断。
换句话说,我们不允许有前面元素小而后面元素大的情况,队胃是更大值,而对头是更小值,也就是“单调” 我们需要的操作是在队尾进行进队和出队,同时我们需要快速获取对头,所以我们使用的数据结构是双端队列,滑动窗口的模板是入队in、出队out、记录答案record ans:

class Solution {
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        deque<int> q;
        vector<int> ans;
        for(int i = 0; i < nums.size(); ++i) {
            // in
            while(!q.empty() && nums[i] >= nums[q.back()]) {
                q.pop_back();
            }
            q.push_back(i);
            // out
            if(q.front() < i - k + 1) {
                q.pop_front();
            }
            // record ans
            if(i - k + 1 >= 0) {
                ans.push_back(nums[q.front()]);
            }
        }
        return ans;
    }
};

347.前 K 个高频元素

最朴素的做法是先统计频次,然后根据频次排序,得到前k个高频元素,时间复杂度为\(O(nlogn)\)但是我们并不需要后面那n-k个元素,所以这里面有优化的地方,哪些元素一定不会作为答案输出呢?如果某个元素已经比k个元素都小了,那么它一定不是最大的k个元素,所以我们可以使用一个小根堆,如果小根堆的大小 >= k+1那么堆顶元素至少比k个元素小,所以一定不是最大的k个元素之一,删掉,直到最后只剩下k个元素

class cmp {
    public: 
    typedef pair<int, int> PII;
    bool operator()(const PII& A, const PII& B) {
        return A.second > B.second;
    }
};
class Solution {
public:
    typedef pair<int, int> PII;
    vector<int> topKFrequent(vector<int>& nums, int k) {
        unordered_map<int, int> mp;
        for(auto& n : nums) {
            mp[n]++;
        }
        priority_queue<PII, vector<PII>, cmp> pri_que;
        for(auto it : mp) {
            pri_que.push(it);
            if(pri_que.size() > k) {
                pri_que.pop();
            }
        }
        vector<int> ans;
        for(int i = k - 1; i >= 0; i--) {
            ans.emplace_back(pri_que.top().first);
            //ans[i] = pri_que.top().first;
            pri_que.pop();
        }
        return ans;
    }
};

posted @ 2024-02-19 10:38  ccnju  阅读(3)  评论(0)    收藏  举报