滑动窗口题目出处(1441)
emmm。。。
因为开始没搞懂双向队列,就用队列模拟,让后就愉快的炸掉。。。。。。
先来给大家推一遍
对于样例:
8 3
1 3 -1 -3 5 3 6 7
其实这道题就是用一个单调双向队列来进行模拟运算。
一个存最大值,一个存最小值。
我们先看最大值,如果有两个数a[i]和a[j],i<j&&a[i]<a[j],那么a[i]就没有用了,对不对?因为不管那个窗口怎样动,只要既有a[i]又有a[j],最差也是输出a[j],而不是a[i]
(留白缓冲区,懂了的可以跳过)
求最小值就是相反的。。。
所以用双向队列模拟一下每个数进入和出去的时候就好了。。。
接下来是介绍双向队列时间,大佬请跳过:
双向队列:deque
头文件:#include<deque>
using namespace std;
定义:deque<类型>名称
常用函数(设此双向队列的函数名为a):
1、a.push_front(x) 对头加入元素x
2、a.push_back(x) 对尾加入元素x
3、a.pop_front() 踢出对头元素
4、a.pop_back() 踢出对尾元素
5、a.front() 返回对头元素
6、a.back() 返回对尾元素
这道题要用的大概就是这些,还想深入了解的请戳
上代码:
#include<cstdio>
#include<deque>
using namespace std;
inline void read(int &x) {
x=0;
int f=1;
char s=getchar();
while(s<'0'||s>'9') {
if(s=='-')
f=-1;
s=getchar();
}
while(s>='0'&&s<='9') {
x=x*10+s-48;
s=getchar();
}
x*=f;
}
inline void pr(int x) {
if(x<0) {
putchar('-');
x=-x;
}
if(x>9)
pr(x/10);
putchar(x%10+48);
}//快读快输不解释
struct node {
int id,num;//num是TA原来的值,id是TA的位置,在判断TA有没有出窗口时会用到
}a[1000005];
deque<node>q;//双向队列,求max
deque<node>s;//双向队列,求min
int i,n,j,k,ansq[1000005],anss[1000005],tot;
int main() {
read(n),read(k);
for(i=1;i<=n;i++)
read(a[i].num),a[i].id=i;
for(i=1;i<=n;i++) {
if(q.empty()/*队列为空当要push*/||q.back().num<a[i].num)//符合这个单调队列的上升性
q.push_back(a[i]);
else if(a[i].num<q.back().num) {
while(!q.empty()&&a[i].num<q.back().num)//维护这个队列的单调性
q.pop_back();//由推理得出的
q.push_back(a[i]);//把这个值push进去
}
if(s.empty()||s.back().num>a[i].num)//s的处理和q是一样的
s.push_back(a[i]);
else if(a[i].num>s.back().num) {
while(!s.empty()&&a[i].num>s.back().num)
s.pop_back();
s.push_back(a[i]);
}
if(i>=k) {//已经要输出的环节
while(i-q.front().id+1>k)//判断在不在窗口里面,大家可以想一想为什么要+1
q.pop_front();
while(i-s.front().id+1>k)//同上
s.pop_front();
ansq[++tot]=q.front().num;//记录答案
anss[tot]=s.front().num;
}
}
for(i=1;i<tot;i++)
pr(ansq[i]),putchar(' ');
pr(ansq[tot]),putchar('\n'),pr(anss[1]);
for(i=2;i<=tot;i++)
putchar(' '),pr(anss[i]);//输出不能有行末多余空格
}
大概就是这样的,不懂的可以讨论一下