随想录训练营11/60 | LC 239. 滑动窗口最大值 ;LC 347.前 K 个高频元素

LC 239. 滑动窗口最大值

题目链接 LC 239. 滑动窗口最大值
思路:用单调队列,不是优先级队列,来解决该问题。单调队列在STL中没有这样的数据结构,需要自己创建。**单调队列应该满足的功能:队列元素应是从大到小排列。**当窗口向后移动时,有元素进窗口,也有元素出窗口。
对于进窗口的元素,若遇到比队列头大的元素就将队列中的元素全部弹出,再让大元素进入队列;若遇到比队列头元素小,比队列尾元素大的,就弹出队尾元素直到比遍历的元素大,再将遍历元素放入队列中;若遇到比队列尾元素还小的元素就直接放到队列尾部。总结,就是从队列尾部开始弹直到队列尾部元素大于准备进栈元素。
对于出窗口的元素,若其值不等于队列头元素(最大值)则不用管,若为队列头元素,则将队列头元素弹出窗口。
在处理完进出窗口元素后,队列头元素就是这个窗口的最大值。
判断虽然有点多,但是比暴力解法快,该思路仅用线性复杂度就可解决。
使用deque比较合适,deque是双向队列。虽然stack和queue不支持迭代器,但是deque支持。deque的STL函数:

deque<int> de;
de.front();
de.back();
de.push_front();
de.push_back();
de.pop_front();
de.pop_back();
de.size();
//还有好多支持迭代器的函数如
de.begin();
de.end();
de.insert();

代码

class Solution {
//先构建一个单调队列
private:
    class MyQueue{
        public:
            //定义一个双向队列
            deque<int> de;
            //双向队列所有用函数
            //进队列    
            void push(int x){
                //x是入窗口元素
                //当队列非空且最后元素小于入栈元素时,弹出队尾元素
                while(!de.empty() && de.back()<x){
                    de.pop_back();
                }
                de.push_back(x);
            }
            //出队列,若出窗口的元素为队列最大元素,则弹出队头元素,否则不用管。
            //为什么可以这样?首先,单调队列中的元素的顺序是按着遍历的顺序来的,所以先进来的必定先出去。
            void pop(int x){
                //x是出窗口元素,要不要判断队列为空都行
                if(!de.empty() && x == de.front())
                    de.pop_front();
            }
            //得到队列头节点
            int front(){
                return de.front();
            }
    };
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        MyQueue que;//创建自己的单调队列
        vector<int> result;//保存结果
        for(int i=0; i<k; ++i){//把前k个先放进栈中
            que.push(nums[i]);
        }
        //保存第一个窗口值
        result.push_back(que.front());
        //遍历后面的值
        for(int i=k; i<nums.size(); ++i){
            que.pop(nums[i-k]);
            que.push(nums[i]);
            result.push_back(que.front());
        }
        return result;
    }
};

LC 347.前 K 个高频元素

题目链接LC 347.前 K 个高频元素
思路:首先遍历vector,构建map,key为vector的值,value为值的个数。然后使用优先级队列(小顶堆或者大顶堆),构造大小为K的优先级队列,因为要保存频率最大的K个元素,所以使用小顶堆合适。每次弹出最小的元素(堆顶元素),最后保存的K个就是最大的。或者不对堆进行pop,只push,用大顶堆保存,最后遍历前k个就可以。
对于堆这种数据结构,每次pop都是从堆顶开始pop,每次push都是从堆底push,然后对堆进行调整。
对于堆,C++有现成的数据结构可以调用为priority_queue,其包含的成员函数有:

//定义priority_queue
priority_queue<int, vector<int>, myCompare> prioQue;//第一个参数为堆包含的元素类型;第二个参数为基础容器的对象类型(用什么容器保存元素);第三个参数为用于对优先级队列排序的比较对象(函数指针或者函数对象)
//myCompare有两种方式:第一种是直接使用STL的仿函数less或者greater;第二种为自己实现
//第一种:直接使用STL的仿函数,适用于简单的数据结构
#include<functional>//这两个函数在头文件functional中
priority_queue<int, vector<int>, less<int>> prioQue;
priority_queue<int, vector<int>, greater<int>> prioQue;
//第二种:自己构建,适用于复杂的数据结构
class myCompare{
public:
	bool operator()(const pair<int, int>& lhs, const pair<int, int>& rhs){
		return lhs.second > rhs.second;//大于号是小顶堆,小于号是大顶堆
	}
};
priority_queue<pair<int, int>, vector<pair<int, int>>, myCompare> prioQue;

prioQue.pop();//弹出第一个元素,堆顶元素,弹出后进行堆的结构调整。弹出的具体流程为:先把堆顶元素与尾元素交换,然后删除尾元素,最后调整树的结构形成新的堆
prioQue.push();//按排序顺序插入新元素,插入元素不用调整结构
prioQue.size();//堆中元素总数
prioQue.top();//返回堆中第一个元素

代码

class Solution {
public:
    class myCompare{
        public:
        bool operator()(const pair<int, int>& a, const pair<int, int>& b){//重载operator运算符可传入无限参数
        //由于传入的是引用,所以需要const
        return a.second > b.second;
        }
    };
    vector<int> topKFrequent(vector<int>& nums, int k) {
        //使用map,将每个整数出现的频率保存下来
        unordered_map<int, int> map;
        // for(int i=0; i<nums.size(); ++i){
        //     map[nums[i]]++;
        // }
        for(int i : nums){
            ++map[i];
        }

        //使用小顶堆保存前k个数据对
        priority_queue<pair<int, int>, vector<pair<int, int>>, myCompare> que;
        // for(unordered_map<int, int>::iterator j=map.begin(); j!=map.end(); ++j){
        //     que.push(*j);
        //     if(que.size()>k)que.pop();//若队列大小大于k,就弹出
        // }
        for(pair<int, int> j : map){
            que.push(j);
            if(que.size() > k)que.pop();
        }

        vector<int> result(k);//大小为k的vector
        for(int m=k-1; m>=0; --m){
            result[m] = que.top().first;
            que.pop();
        }
        return result;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值