滑动窗口
前三次
第二次 2020.09.22
第三次 2020.11.15
第四次 2020-11-15
简单地说就死维护一个单调队列,每次输出队尾即可。
#include <iostream>
using namespace std;
const int N = 1000010;
int a[N], q[N];
int main()
{
int n, k;
scanf("%d%d", &n, &k);
for (int i = 0; i < n; i ++ ) scanf("%d", &a[i]);
//这里处理的是最小值
int hh = 0, tt = -1//头 和 尾
for (int i = 0; i < n; i ++ )
{
if (hh <= tt && i - k + 1 > q[hh] ) hh ++ ;
//这里是当队列里面还有元素 以及 头不在这个窗口范围的时候,头就往后走一位
while (hh <= tt && a[q[tt]] >= a[i] ) tt -- ;
//这里是要把队列中所有比 现在要插入的元素 大的元素出队
//然后就会发现 现在队列里的元素 正是当前状态(加入新元素)的单调队列
q[ ++ tt] = i;
if (i >= k - 1) printf("%d ", a[q[hh]]);
//队头是最小的
}
puts("");
//这里处理的是最大值
hh = 0, tt = -1;
for (int i = 0; i < n; i ++ )
{
if (hh <= tt && i - k + 1 > q[hh]) hh ++ ;
while (hh <= tt && a[q[tt]] <= a[i]) tt -- ;
q[ ++ tt] = i;
if (i >= k - 1) printf("%d ", a[q[hh]]);
}
puts("");
return 0;
}
这里是调试模板,可以看到队列的变化(还蛮有意思的)
#include <bits/stdc++.h>
using namespace std;
const int N = 1000010;
int a[N], q[N];
int hh = 0, tt = -1;
void out(){
// for(int i = 0; i < O1; i ++)
// printf("%d ", q[i]);
// puts("");
printf("当前队列\n");
for(int i = hh; i <= tt; i ++)
printf("%d ", a[q[i]] );
puts("");
puts("");
}
int main()
{
freopen("ttt.in", "r", stdin);
freopen("ttt.out", "w", stdout);
int n, k;
scanf("%d%d", &n, &k);
for (int i = 0; i < n; i ++ ) scanf("%d", &a[i]);
int hh = 0, tt = -1;
for (int i = 0; i < n; i ++ )
{
if (hh <= tt && i - k + 1 > q[hh])
hh ++ ;
printf("当前队列\n");
for(int i = hh; i <= tt; i ++)
printf("%d ", a[q[i]] );
puts("");
puts("");
while (hh <= tt && a[q[tt]] >= a[i]){
tt -- ;
printf("当前队列\n");
for(int i = hh; i <= tt; i ++)
printf("%d ", a[q[i]] );
puts("");
puts("");
}
q[ ++ tt] = i;
printf("当前队列\n");
for(int i = hh; i <= tt; i ++)
printf("%d ", a[q[i]] );
puts("");
puts("");
if (i >= k - 1)
printf("________%d \n\n\n", a[q[hh]]);
}
puts("");
return 0;
}
第四次(这次是用deque做哒!)
以下是四种定义deque的方法
// 直接定义
std::deque<int> first; // empty deque of ints
//填充数字
std::deque<int> second (4,100); // four ints with value 100
//The contents of second are: 100 100 100 100
//复制某双端队列的某一段
std::deque<int> third (second.begin(),second.end()); // iterating through second
//The contents of third are: 100 100 100 100
//或者直接复制下整个其它双端队列
std::deque<int> fourth (third); // a copy of third
//The contents of fourth are: 100 100 100 100
//或者复制某个数组
// the iterator constructor can be used to copy arrays:
int myints[] = {16,2,77,29};
std::deque<int> fifth (myints, myints + sizeof(myints) / sizeof(int) );
//The contents of fifth are: 16 2 77 29
具体使用
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
int a[N];
//不要给双端队列q定义大小,我也不清楚
deque<int>q;
int main(){
//个数,窗口大小
int n, k; cin >> n >> k;
for(int i = 1; i <= n; i ++) scanf("%d", &a[i]);
//递增
//依次将数组元素入队
for(int i = 1; i <= n; i ++){
//首先是出队操作
while( !q.empty() && a[i] < a[q.back()]) q.pop_back();
q.push_back(i);
if(!q.empty() && q.front() < i - k + 1) q.pop_front();
if(!q.empty() && i >= k) printf("%d ", a[q.front()]);
}
puts("");
//递减
q.clear();
for(int i = 1; i <= n; i ++){
//首先是出队操作
while( !q.empty() && a[i] > a[q.back()]) q.pop_back();
q.push_back(i);
if(!q.empty() && q.front() < i - k + 1) q.pop_front();
if(!q.empty() && i >= k) printf("%d ", a[q.front()]);
}
puts("");
return 0;
}
低配版滑动窗口
这次是在周测10做的,只用到单调递减队列。
#include<bits/stdc++.h>
using namespace std;
const int N = 3e6 + 10;
deque<int>q;
int a[N];
int main(){
int n, k;
cin >> n >> k;
for(int i = 1; i <= n; i ++) scanf("%d", &a[i]);
for(int i = 1; i <= n; i ++){
//首先当然是维护队列的单调性啦!
while(!q.empty() && a[i] > a[q.back()]) q.pop_back();
if(!q.empty() && q.front() < i - k + 1) q.pop_front();
q.push_back(i);
if(i >= k) printf("%d\n", a[q.front()] );
}
return 0;
}