LeetCode刷题笔记【8】:栈&队列专题-3(滑动窗口最大值, 前k个高频元素)

前置知识

参考前文:
LeetCode刷题笔记【6】:栈&队列专题-1(用栈实现队列, 用队列实现栈)
LeetCode刷题笔记【7】:栈&队列专题-2(有效的括号, 删除字符串的所有相邻重复项, 逆波兰表达式求值)

239. 滑动窗口最大值

题目描述

在这里插入图片描述

LeetCode链接:https://leetcode.cn/problems/sliding-window-maximum/

解题思路

思路: 使用deque实现一个“伪单调队列”;
因为题目要求每次都取这个区间内最大的,所以我们并不需要将区间内所有的数都加入队列并进行排序;
只需要将最有可能成为答案的几个最大数加入备选即可;
并且还需要在窗口滑动的过程中识别被抛出窗口的数,将其移出队列;

具体的操作为:push新数x时,empty则直接push,非empty时,如果队尾数小于x,就pop_back, 直到队尾数大于等于x, 或empty;
pop老数x时, 如果x等于front, 就pop_front, 否则无操作;

代码

class Solution {
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        int n=nums.size();
        vector<int> ans;
        deque<int> que;
        for(int i=0; i<k; ++i){
            while(!que.empty() && que.back()<nums[i])
                que.pop_back();
            que.push_back(nums[i]);
        }
        ans.push_back(que.front());
        for(int i=0, j=k; j<n; ++i, ++j){
            // pop the old num
            if(!que.empty() && nums[i]==que.front())
                que.pop_front();
            // push the new num
            while(!que.empty() && que.back()<nums[j])
                que.pop_back();
            que.push_back(nums[j]);
            ans.push_back(que.front());
        }
        return ans;
    }
};

347.前 K 个高频元素

题目描述

在这里插入图片描述

LeetCode链接:https://leetcode.cn/problems/top-k-frequent-elements/

快速排序法

思路: 先用unordered_map记录数字出现的频率;
然后将频率导入vector<pair<int出现次数,int对应数字>> counter
然后使用:

sort(counter.begin(), counter.end(), [](const pair<int, int>& a, const pair<int, int>& b) {
return a.first < b.first;
 });

进行从大到小的排序, 然后再将前k个元素导入vector<int> ans

class Solution {
public:
    vector<int> topKFrequent(vector<int>& nums, int k) {
        unordered_map<int,int> map;
        for(int i=0; i<nums.size(); ++i){
            map[nums[i]]++;
        }
        vector<pair<int,int>> counter;
        for(auto& element : map){
            pair tmp = make_pair(element.second, element.first);
            counter.push_back(tmp);
        }
        sort(counter.begin(), counter.end(), [](const pair<int, int>& a, const pair<int, int>& b) {
        return a.first > b.first;
        });
        vector<int> ans;
        for(int i=0; i<k; ++i){
            ans.push_back(counter[i].second);
        }
        return ans;
    }
};

优先队列(小根堆)法

思路: 还是先用unordered_map记录频率, 然后建立一个优先队列(小根堆) priQ;
保持priQ中元素数量为k, 如果不足k, 新元素直接入堆;
如果等于k, 比较新元素x和堆顶元素top;
x<top则丢弃x, x>top则弹出top并入堆x;
但是实际操作上, 是直接入堆x, 然后如果size>k, 就弹出top(反正top是最小的);

class Solution {
public:
    class Compare{
    public: bool operator()(pair<int,int> a, pair<int,int> b){
            return a.second > b.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>>, Compare> priQ;
        for(const auto& pair : map){
            priQ.push(pair);
            if(priQ.size()>k)
                priQ.pop();
        }

        vector<int> ans;
        for(int i=0; i<k; ++i){
            ans.push_back(priQ.top().first);
            priQ.pop();
        }
        return ans;
    }
};

总结

不同的数据结构有适合其解决的典型问题;
一方面很多时候需要用最合适的工具干最合适的事儿, 另一方面当对一部分工具掌握熟练以后, 也可以通过不那么优雅的方式, 解决很多其他问题.

本文参考:
239. 滑动窗口最大值
347.前 K 个高频元素

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值