欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

week5 D题滑动窗口 单调队列

程序员文章站 2022-05-04 17:16:07
...

题目:
ZJM 有一个长度为 n 的数列和一个大小为 k 的窗口, 窗口可以在数列上来回移动. 现在 ZJM 想知道在窗口从左往右滑的时候,每次窗口内数的最大值和最小值分别是多少.
例如:数列是[1 3 -1 -3 5 3 6 7], 其中k 等于 3.
week5 D题滑动窗口 单调队列
输入:
输入有两行。第一行两个整数n和k分别表示数列的长度和滑动窗口的大小,1<=k<=n<=1000000。第二行有n个整数表示ZJM的数列。
输出:
输出有两行。第一行输出滑动窗口在从左到右的每个位置时,滑动窗口中的最小值。第二行是最大值。
样例输入:
8 3
1 3 -1 -3 5 3 6 7
样例输出:
-1 -3 -3 -3 3 3
3 3 5 5 6 7

本题可以用两个单调队列解决,一个是单调递增的队列,一个是单调递减的队列。
比如求最大值,根据窗口大小k,先循环将k个元素压入单调递减的队列,如果队列为空,则元素压入,如果队列末尾元素小于要压入的队列,则将末尾元素弹出,直到末尾元素大于当前要压入的元素,则队首元素为当前窗口内最大的元素。此外,还要考虑在窗口移动过程中是否有元素即使在压入新元素的过程中没有被弹出,但是已经陈旧了,即在窗口的左外部,这种元素也要弹出。同时,因为越靠近队首的元素序号越靠前,可以依据队首的序号判断元素是否过于陈旧,只需要判断一次,因为窗口一次移动一位。
此外,对于本题,要使用scanf和printf进行输入输出,用cin和cout会超时。

以下是完整代码:

#include<iostream>
using namespace std;
struct node{
 int rank;
 int ele;
};
class Maxqueue{
 private:
  int first,last;
  node *q;
 public:
  Maxqueue()
  {
   first=0;
   last=0;
   q=new node[2000000];
  }
  int back()
  {
   return q[last-1].ele;
  }
  int front()
  {
   return q[first].ele;
  }
  bool empty()
  {
   return first==last;
  }
  void pop_back()
  {
   last--;
  }
  void push_back(node x)
  {
   if(!empty())//在队列不空的情况下才可以用back()函数 
   {
    while(!empty()&&back()<x.ele)//将队尾所有小于x的元素弹出 
    {
     pop_back();
    }
   }
   
   q[last].ele=x.ele;
   q[last++].rank=x.rank;
  }
  int front_rank()
  {
   return q[first].rank;
  }
  void pop_front()
  {
   first++;
  }
};
class Minqueue{
 private:
  int first,last;
  node *q;
 public:
  Minqueue()
  {
   first=0;
   last=0;
   q=new node[2000000];
  }
  int back()
  {
   return q[last-1].ele;
  }
  int front()
  {
   return q[first].ele;
  }
  bool empty()
  {
   return first==last;
  }
  void pop_back()
  {
   last--;
  }
  void push_back(node x)
  {
   if(!empty())
   {
    while(!empty()&&back()>x.ele)
    {
     pop_back();
    }
   }
   
   q[last].ele=x.ele;
   q[last++].rank=x.rank;
  }
  int front_rank()
  {
   return q[first].rank;
  }
  void pop_front()
  {
   first++;
  }
};

node a[2000000];
int main()
{
 Maxqueue maq;
 Minqueue miq;
 int n,k;
 cin>>n>>k;
  for(int i=0;i<n;i++)
 {
  scanf("%d",&a[i].ele);
  a[i].rank=i;//保存元素的序号 
 }
 for(int i=0;i<k;i++)
 {
  maq.push_back(a[i]);
  miq.push_back(a[i]); 
 }
 int l=0,r=k-1;
 while(r<n)
 {
  printf("%d ",miq.front());//输出窗口内的最小值 
  l++;
  r++;
  if(miq.front_rank()<r-k+1)//判断队首元素是否已经过于陈旧 
  {
   miq.pop_front();//弹出 
  }
  miq.push_back(a[r]);
 }
 cout<<'\n';
  l=0,r=k-1;
 while(r<n)//与上面类似 
 {
  printf("%d ",maq.front());
  l++;
  r++;
  if(maq.front_rank()<r-k+1)
  {
   maq.pop_front();
  }
  maq.push_back(a[r]);
 }
}