滑动窗口
题目描述
核心思路
- 维护单调队列从队头到队尾是严格单调递减的,那么队头就是最大值
- 维护单调队列从队头到队尾是严格单调递增的,那么队头就是最小值
代码
写法1:下标从1开始
#include<iostream>
using namespace std;
const int N = 1000010;
int a[N],q[N];
int n,k;
int main()
{
cin >>n>>k;
for(int i=1;i<=n;i++)
cin >>a[i];
int hh=0,tt=-1;
for(int i=1;i<=n;i++)
{
if(hh<=tt&&q[hh]<i-k+1)
hh++;
while(hh<=tt&&a[i]<=a[q[tt]])
tt--;
q[++tt]=i;
if(i>k-1)
printf("%d ",a[q[hh]]);
}
cout <<endl;
hh=0,tt=-1;
for(int i=1;i<=n;i++)
{
if(hh<=tt&&q[hh]<i-k+1)
hh++;
while(hh<=tt&&a[i]>=a[q[tt]])
tt--;
q[++tt]=i;
if(i>k-1)
printf("%d ",a[q[hh]]);
}
return 0;
}
#include<iostream>
using namespace std;
const int N = 1000010;
int a[N],q[N];
int n,k;
int main()
{
cin >>n>>k;
for(int i=1;i<=n;i++)
cin >>a[i];
int hh=0,tt=-1;
for(int i=1;i<=n;i++)
{
if(hh<=tt&&q[hh]<i-k+1)
hh++;
while(hh<=tt&&a[i]<=a[q[tt]])
tt--;
q[++tt]=i;
if(i>=k)
printf("%d ",a[q[hh]]);
}
cout <<endl;
hh=0,tt=-1;
for(int i=1;i<=n;i++)
{
if(hh<=tt&&q[hh]<i-k+1)
hh++;
while(hh<=tt&&a[i]>=a[q[tt]])
tt--;
q[++tt]=i;
if(i>=k)
printf("%d ",a[q[hh]]);
}
return 0;
}
写法2:下标从0开始
#include<iostream>
using namespace std;
const int N = 1000010;
int a[N],q[N];
int n,k;
int main()
{
cin >>n>>k;
for(int i=0;i<n;i++)
cin >>a[i];
int hh=0,tt=-1;
for(int i=0;i<n;i++)
{
if(hh<=tt&&q[hh]<i-k+1)
hh++;
while(hh<=tt&&a[i]<=a[q[tt]])
tt--;
q[++tt]=i;
if(i>=k-1)
printf("%d ",a[q[hh]]);
}
cout <<endl;
hh=0,tt=-1;
for(int i=0;i<n;i++)
{
if(hh<=tt&&q[hh]<i-k+1)
hh++;
while(hh<=tt&&a[i]>=a[q[tt]])
tt--;
q[++tt]=i;
if(i>=k-1)
printf("%d ",a[q[hh]]);
}
return 0;
}
写法3:deque双端队列
#include<iostream>
#include<deque>
using namespace std;
const int N=1e6+10;
int n,k;
int a[N];
deque<int>q;
int main()
{
cin >>n>>k;
for(int i=0;i<n;i++)
cin >>a[i];
//要求窗口内的最小值,设置单调队列,队列内的元素是严格单调递减的,队头元素就是窗口的最小值
for(int i=0;i<n;i++)
{
//当队列不空,并且如果q.front不在窗口[i-m+1,i]中,则队头出队
if(!q.empty()&&q.front()<i-k+1)
q.pop_front();
//当队头元素不为空,并且新来的元素a[i]小于等于队尾元素时,队尾元素出队
while(!q.empty()&&a[i]<=a[q.back()])
q.pop_back();
//到这里说明这个新元素可以直接加入队列中,下标入队
q.push_back(i);
//当达到窗口的大小k时才能输出,比如窗口大小k=3,那么刚开始窗口为0,1时,窗口大小为2,不足题目给定的窗口大小k=3,不能输出
if(i>=k-1)
printf("%d ",a[q.front()]);
}
q.clear();//情况上面的deque队列
cout <<endl;
//要求窗口内的最大值,设置单调队列,队列内的元素是严格单调递增的,队头元素就是窗口的最大值
for(int i=0;i<n;i++)
{
//当队列不空,并且如果q.front不在窗口[i-m+1,i]中,则队头出队
if(!q.empty()&&q.front()<i-k+1)
q.pop_front();
//当队头元素不为空,并且新来的元素a[i]大于等于队尾元素时,队尾元素出队
while(!q.empty()&&a[i]>=a[q.back()])
q.pop_back();
//到这里说明这个新元素可以直接加入队列中,下标入队
q.push_back(i);
//当达到窗口的大小k时才能输出,比如窗口大小k=3,那么刚开始窗口为0,1时,窗口大小为2,不足题目给定的窗口大小k=3,不能输出
if(i>=k-1)
printf("%d ",a[q.front()]);
}
return 0;
}