算法训练营第十三天 | 239. 滑动窗口最大值、347.前 K 个高频元素

文章目录

    • 对应力扣的题目链接
    • 思路分析
    • 解决方案

问题一 、239. 滑动窗口最大值

题目链接  239. 滑动窗口最大值 - 力扣(LeetCode)

思路分析 :

              1、可能首先想到的是暴力破解 ,每一个区间,遍历一遍,找到最大值。将其搜集起来。

              2、单调队列的思想 ,每次窗口移动的时候,调用que.pop(滑动窗口中移除元素的数                      值),que.push(滑动窗口添加元素的数值),然后que.front()就返回我们要的最大值。

              3、 当然这个队列是没有的,具体功能需要我们自己实现。

单调队列的实现(  基于一个双向队列  deque  可以对对头和队尾进行操作 )
my_push( )   入队 :

入队之前和队列中元素进行比较,如果队列中的元素比要入队的元素小,则将其出队。

这样我们队列的对头元素总是最大值,然后我们滑动窗口移动的时候,每次都从对头拿去窗口的最大值。

void  my_push( int value ){
    
    while( !my_queue.empty()  && my_queue.back() < value){
          my_queue.pop_back();
    }
    my_queue.push_back( value );
}

// my_queue  是我们定义的一个私有成员, 他是 deque 类型

my_pop( )   出队 :

因为我们在入队的时候,就已经将较小的元素出队了。

所以这里我们处理的是,如果窗口移除的元素value等于单调队列的出口元素,则将其出队。

 //出队
 void my_pop(int value){
     //当我们要入队的元素和队头元素相等时,说明要丢弃的是之前队列里面的最大值
     if(!my_queue_.empty() && value==myDeque_.front()){
          myDeque_.pop_front() ;
     }
 }

视频和更详细的文字讲解(代码随想录)

代码随想录

具体解决方案:

class Solution {
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        myDeque myDeque_;
        vector< int >data;

        if( nums.size() < k )  return data;

        //先放入前k个元素
        for( int i = 0 ; i < k ; i++ ){
            myDeque_.my_push(nums[i]);
        }
        //找到前k个的最大值

        data.push_back( myDeque_.getMax() );
        for(int i=k ; i< nums.size() ; i++ ){
            myDeque_.my_pop( nums[i-k] );     //
            myDeque_.my_push( nums[i] );
           data.push_back( myDeque_.getMax() );
        }
        return data;
    }

private:
class myDeque{
    public:
    deque< int >myDeque_;    //定义一个双向队列
    //出队
    void my_pop(int value){
        //当我们要入队的元素和队头元素相等时,说明要丢弃的是之前队列里面的最大值
        if(myDeque_.empty()!=true && value==myDeque_.front()){
            myDeque_.pop_front() ;
        }
    }
    //入队
    void my_push(int value){
        while( myDeque_.empty()!=true && value > myDeque_.back() ){
            myDeque_.pop_back();
        }
        myDeque_.push_back(value);
    }
    
    int getMax(){
        return myDeque_.front();
    }
};
 
};

问题二 、347.前 K 个高频元素 

题目链接:

347. 前 K 个高频元素 - 力扣(LeetCode)

思路分析:

  • 遇到一个数出现的次数,我们首先想到 使用map 这个容器,key 记录要计算的数,value 出现的次数
  • 优先级队列(底层是实现是一个堆),将map中的数据进行排序,采用小顶堆
  • 最后反向输入到需要返回的数组中

视频和更详细的文字讲解(代码随想录):

代码随想录

解决方案:

class Solution {
public:
//自定义比较函数
class MyCompare{
    public:
        bool operator()(const pair<int ,int>&left , const pair<int ,int>&right){
            return left.second > right.second;
        }
};

    vector<int> topKFrequent(vector<int>& nums, int k) {
       
       // if(nums.size() < k ) return ret;
        unordered_map< int ,int >temp;
        // key 是数字, value是出现的次数
        for(int i=0 ; i<nums.size() ; i++){
            temp[ nums[i] ]++;
        }
       // 排序使用 ,小顶堆(优先级队列)
        priority_queue<pair<int, int>, vector<pair<int, int>>, MyCompare > pq;
       //将map中的数据放入优先级队列,并从小到大排序
       for(unordered_map<int,int>::iterator it = temp.begin() ; it!=temp.end() ; it++){
           pq.push(*it);
           if(pq.size() >k ){
               pq.pop();      //将最小的值出队
           }
           //入队,并排序
         
       }
       //将队列中的数据导入ret
        vector<int>ret(k);
       for( int i=k-1 ; i>=0 ;i--  ){
           ret[i]=pq.top().first;
           pq.pop();
       }
        return ret;
    }
};

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

零二年的冬

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值