问题:
题目来自牛客网~
方法:
设数组元素为ai
解决这个题采用了双向队列,思路的话以求最大值为例,建立一个队列,然后遍历每个a[i],重复执行下面两个步骤:
1.如果a[i] > 队尾的元素(说明队尾这个元素已经没有了成为最大值的可能),删除队尾元素,直到队尾元素 > a[i] 或者 队列为空
如果a[i] < 队尾的元素(则当窗口滑动到这个队尾元素失效的时候,a[i] 有可能成为最大值),将a[i] 放入队列
如果此时 i >= k(窗口满元素) ,输出队头元素
2.从队头位置开始将所有不在窗口范围内的元素删除,因为滑动窗口只是同时判断 k 个元素的最大值
因为队列里直接放置 a[i] 的时候执行操作 2 会不方便,所以我们选择在队列里存放元素的下标 i
最小值同理
代码:
使用STL里 deque 的写法:
#include <iostream>
#include <deque>
#include <cstdio>
using namespace std;
#define N 1000010
deque <int>q_max;
deque <int>q_min;
int n, k, a[N];
int main(void)
{
scanf("%d%d", &n,&k);
for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
//min
for(int i = 1; i <= n; i++){
//去掉不在窗口内的元素
while(i-q_min.front() >= k) q_min.pop_front();
//a[i] < 队尾元素,删除队尾开始所有小于a[i]的元素
while(!q_min.empty() && a[i] < a[q_min.back()]) q_min.pop_back();
q_min.push_back(i);
if(i >= k) cout <<a[q_min.front()] <<" ";
}
cout <<endl;
//max
for(int i = 1; i <= n; i++){
//去掉不在窗口内的元素
while(i-q_max.front() >= k) q_max.pop_front();
//a[i] > 队尾元素,删除队尾开始所有小于a[i]的元素
while(!q_max.empty() && a[i] > a[q_max.back()]) q_max.pop_back();
q_max.push_back(i);
if(i >= k) cout <<a[q_max.front()] <<" ";
}
return 0;
}
使用数组模拟队列写法:
#include <iostream>
#include <cstring>
using namespace std;
#define N 100010
int n, k;
int q[N], a[N];
int main(void)
{
//输入
scanf("%d%d", &n, &k);
for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
int head = 1, tail = 0;
for(int i = 1; i <= n; i++){
//丢掉不在窗口内的元素
if(tail >= head && i - q[head] + 1 > k) head++;
//删去不符合条件的尾部元素
while(tail >= head && a[q[tail]] >= a[i]) tail--;
//将元素放进队列
q[++tail] = i;
//输出
if(i >= k)
cout <<a[q[head]] <<" ";
}
cout <<endl;
head = 1, tail = 0;
for(int i = 1; i <= n; i++){
//丢掉不在窗口内的元素
if(tail >= head && i - q[head] + 1 > k) head++;
while(tail >= head && a[q[tail]] <= a[i]) tail--;
q[++tail] = i;
if(i >= k){
cout <<a[q[head]] <<" ";
}
}
return 0;
}