单调队列解决滑动窗口最大值

文章目录

  • 1 单调队列
  • 2 leetcode239 滑动窗口最大值

1 单调队列

 单调队列,顾名思义,是维护一个单调递增的或单调递减的队列,比较容易地想到可以使用deque来维护这个单调队列,这是因为deque可以在头尾进行插入和删除。这里我们可以维护一个单调递减的队列。插入元素时,将队列中所有比它小的元素删除即可。这里我们只封装push,pop,getmax这三个方法,如下,就可以看出为什么是一个单调递减队列。数组元素是:[1,3,-1,-3,5,3,6,7]
单调队列解决滑动窗口最大值_第1张图片

class MonotonicQueue 
{
public:
  void push(int x)
  {
      //保持单调性,删除比新元素x小的所有元素
      while(!dq.empty()&&x>dq.back())
        dq.pop_back();
    dq.push_back(x);
  }
  int getmax()
  {
    return dq.front();
  }
  void pop()
  {
      dq.pop_front();
  }
 private:
  deque<int> dq;
};

当然,如果想维护一个单调递增的队列,我们只需在push的时候,将所有比新元素大的元素删除,随后在push新元素。

2 leetcode239 滑动窗口最大值

 给定一个数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
返回滑动窗口中的最大值。
如果是暴力解法的话,时间复杂度为 O ( N K ) O(NK) O(NK),空间复杂度为 O ( 1 ) O(1) O(1)

vector<int> maxSlidingWindow(const vector<int>& nums, unsigned int k)
    {
       if(nums.size()==0)
           return {};
        vector<int> ret;
        //一共nums.size()-k+1个滑动窗口
        for(int i=0;i<nums.size()-k+1;i++)
        {
            int Max=-1;
            for(int j=i;j<k+i;j++)
            {
                 Max=max(nums[j],Max);
            }
            ret.push_back(Max);
        }
        return ret;
    }

如果k很大的时候,时间复杂度就是 O ( n 2 ) O(n^2) O(n2)
 我们可以使用一个单调递减的队列,这样我们就不需要每次进行k-1次比较,时间复杂度降到 O ( n ) O(n) O(n),空间复杂度为 O ( n ) O(n) O(n)


class MonotonicQueue 
{
public:
  void push(int x)
  {
      //保持单调性,删除比新元素x小的所有元素
      while(!dq.empty()&&x>dq.back())
        dq.pop_back();
    dq.push_back(x);
  }
  int getmax()
  {
    return dq.front();
  }
  void pop()
  {
      dq.pop_front();
  }
 private:
  deque<int> dq;
};
class Solution {
public:
//单调队列优化
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
         if(nums.size()==0)
              return {};
       MonotonicQueue mq;
        vector<int> ans;
          for(int i=0;i<nums.size();i++)
          {
              mq.push(nums[i]);
              if(i-k+1>=0)
              {
                  ans.push_back(mq.getmax());
                  if(mq.getmax()==nums[i-k+1])
                  mq.pop();
              }
          }
          return ans;
    }

};

当然,我们也不必特地维护一个单调队列,直接在push或pop时判断即可,只是这样更好理解。

你可能感兴趣的:(单调队列解决滑动窗口最大值)