Sliding Window
Description
An array of size n ≤ 106 is given to you. There is a sliding window of sizek which is moving from the very left of the array to the very right. You can only see thek numbers in the window. Each time the sliding window moves rightwards by one position. Following is an example:
The array is [1 3 -1 -3 5 3 6 7], and k is 3.
Window position | Minimum value | Maximum value |
---|---|---|
[1 3 -1] -3 5 3 6 7 | -1 | 3 |
1 [3 -1 -3] 5 3 6 7 | -3 | 3 |
1 3 [-1 -3 5] 3 6 7 | -3 | 5 |
1 3 -1 [-3 5 3] 6 7 | -3 | 5 |
1 3 -1 -3 [5 3 6] 7 | 3 | 6 |
1 3 -1 -3 5 [3 6 7] | 3 | 7 |
Your task is to determine the maximum and minimum values in the sliding window at each position.
Input
The input consists of two lines. The first line contains two integersn andk which are the lengths of the array and the sliding window. There aren integers in the second line.
Output
There are two lines in the output. The first line gives the minimum values in the window at each position, from left to right, respectively. The second line gives the maximum values.
Sample Input
8 3 1 3 -1 -3 5 3 6 7
Sample Output
-1 -3 -3 -3 3 3 3 3 5 5 6 7
题目大意
求一段区间内的最小值和最大值
解题思路
单调队列的简单应用
单调队列,顾名思义,就是一个元素单调的队列,那么就能保证队首的元素是最小(最大)的,从而满足动态规划的最优性问题的需求。
单调队列,又名双端队列。双端队列,就是说它不同于一般的队列只能在队首删除、队尾插入,它能够在队首、队尾同时进行删除。
一般,在动态规划的过程中,单调队列中每个元素一般存储的是两个值:
1. 在原数列中的位置(下标)
2. 他在动态规划中的状态值
而单调队列则保证这两个值同时单调。
我们维护这样一个队列:队列中的每个元素有两个域{position,value},分别代表他在原队列中的位置和数值 ,我们随时保持这个队列中的元素两个域都单调递增。
那计算的时候,只要在队首不断删除,直到队首的 position 大于等于i-m+1 ,那此时队首元素的值必定是不二人选,因为队列是单调的!
我们看看怎样将 a[i]插入到队列中:首先,要保证 position 单调递增,由于我们动态规划的过程总是从1-n的(反之亦然),所以能保证position的单调增。又因为要保证队列的 value 单调递增,所以将队尾元素不断删除,直到队尾元素小于 a[i],然后将a[i]入队。
代码
#include<cstdio>
#include<iostream>
#include<deque>
using namespace std;
struct node
{
int p;
int val;
}a[1000010];
int mmax[1000010];
int mmin[1000010];
deque <node> q1,q2;
int main()
{
int i,j,k,n;
scanf("%d%d",&n,&k);
for(i=1;i<=n;++i)
{
scanf("%d",&a[i].val);
a[i].p=i;
}
//处理最小
for(i=1;i<=n;++i)
{
while(!q1.empty())
{
if(q1.back().val > a[i].val) q1.pop_back();
else break;
}
q1.push_back(a[i]);
while(!q1.empty())
{
if(q1.front().p<i-k+1) q1.pop_front();
else break;
}
mmin[i]=q1.front().val;
}
//处理最大
for(i=1;i<=n;++i)
{
while(!q2.empty())
{
if(q2.back().val < a[i].val) q2.pop_back();
else break;
}
q2.push_back(a[i]);
while(!q2.empty())
{
if(q2.front().p<i-k+1) q2.pop_front();
else break;
}
mmax[i]=q2.front().val;
}
//处理输出
for(i=k;i<n;++i)
{
printf("%d ",mmin[i]);
}
printf("%d\n",mmin[n]);
for(i=k;i<n;++i)
{
printf("%d ",mmax[i]);
}
printf("%d\n",mmax[n]);
return 0;
}