Description
An array of size n ≤ 106 is given to you. There is a sliding window of size k which is moving from the very left of the array to the very right. You can only see the k 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 integers n and k which are the lengths of the array and the sliding window. There are n 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
题意:求从k位置开始,求每个位置的【i-k+1,i】区间内的最大最小值 |
思路(单调队列) :
按照题意,要求每个位置的前k个元素内的最大最小值,那就要不断地更新这k个元素,并满足先进先出的关系(k个之前的元素都要淘汰),所以会想到借助队列。那么这个队列应该要满足怎么样的性质才能对答案有针对性呢?
我们想构造这样一个队列,使得取最大值的时候,取出队头就可以( O(1)) ,同时,这个队列应该满足前面的元素都是下标比较小的,换句话说,队列从头到尾下标依次递增(不一定连续),这样就可以通过循环丢掉队头,使得队内元素都在k范围内。
这样,不难想到,借助一个STL的双端队列(比较懒就不自己数组模拟了),在取最大值的时候,构造一个单调递减的队列,每个a[i]如果比队尾小,就直接push进队尾,否则把前面比它小的都pop掉(从队尾开始),因为前面比它小的对i后面的取最大值没有贡献(我a[i]都比a[i-1]大了,最大值肯定不会是a[i-1]呀,所以这个位置丢掉)。 然后每次i处理完后就取一次队头,就是当前i的答案了。反之亦然
AC代码:
#include<iostream>
#include<string>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include <queue>
#include<sstream>
#include <stack>
#include <set>
#include<vector>
#define FAST ios::sync_with_stdio(false)
#define abs(a) ((a)>=0?(a):-(a))
#define sz(x) ((int)(x).size())
#define all(x) (x).begin(),(x).end()
#define mem(a,b) memset(a,b,sizeof(a))
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define rep(i,a,n) for(int i=a;i<=n;++i)
#define per(i,n,a) for(int i=n;i>=a;--i)
#define pb push_back
#define mp make_pair
#define fi first
#define se second
using namespace std;
typedef pair<int,int> PII;
typedef long long ll;
const int maxn = 1e6+5;
const int inf=0x3f3f3f3f;
const double eps = 1e-7;
const double pi=acos(-1.0);
const int mod = 1e9+7;
inline int lowbit(int x){return x&(-x);}
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
void ex_gcd(ll a,ll b,ll &d,ll &x,ll &y){if(!b){d=a,x=1,y=0;}else{ex_gcd(b,a%b,d,y,x);y-=x*(a/b);}}//x=(x%(b/d)+(b/d))%(b/d);
inline ll qpow(ll a,ll b,ll MOD=mod){ll res=1;a%=MOD;while(b>0){if(b&1)res=res*a%MOD;a=a*a%MOD;b>>=1;}return res;}
inline ll inv(ll x,ll p){return qpow(x,p-2,p);}
inline ll Jos(ll n,ll k,ll s=1){ll res=0;rep(i,1,n+1) res=(res+k)%i;return (res+s)%n;}
inline ll read(){ ll x = 0;char ch = getchar();while(ch>'9'||ch<'0') ch = getchar();while(ch>='0'&&ch<='9') x = (x<<3) + (x<<1) + ch - '0', ch = getchar();return x; }
int dir[4][2] = { {1,0}, {-1,0},{0,1},{0,-1} };
ll a[maxn];
deque<ll> q1;
deque<ll> q2;
ll n; ll k;
void init()
{
while(!q1.empty()) q1.pop_back();
while(!q2.empty()) q2.pop_back();
}
void solve()
{
rep(i,1,n) //从小到大
{
if(q1.empty()||a[i]>a[q1.back()]) //如果队空或者当前比队尾要大,直接放进来
q1.push_back(i);
else //否则
{
while(q1.size()&& (a[q1.back()]>=a[i]||q1.back()+k-1<i)) //说明前面比它大的那些对后面的“前k个"没有作用(作用被当前承包),pop掉
q1.pop_back();
q1.push_back(i); //最后它前面要么是空的要么是比它小的
}
if(i>k)
{
while(q1.size()&&q1.front()<i-k+1)
q1.pop_front(); //k+1位开始每次pop掉i-k之前的
printf("%lld%c",a[q1.front()], i==n?'\n':' ');
}
else if (i==k)
printf("%lld%c",a[q1.front()], i==n?'\n':' '); //k的时候就输出队头
}
while(!q1.empty()) q1.pop_back();
rep(i,1,n) //从大到小,取队头最大的
{
if(q1.empty()||a[i]<a[q1.back()]) //如果队空或者当前比队尾要小,直接放进来
q1.push_back(i);
else //否则
{
while(q1.size()&& (a[q1.back()]<=a[i]||q1.back()+k-1<i)) //说明前面比它小的那些对后面的“前k个最大"没有作用(作用被当前承包),pop掉
q1.pop_back();
q1.push_back(i); //最后它前面要么是空的要么是比它大的
}
if(i>k)
{
while(q1.size()&&q1.front()<i-k+1)
q1.pop_front(); //k+1位开始每次pop掉i-k之前的
printf("%lld%c",a[q1.front()], i==n?'\n':' ');
}
else if (i==k)
printf("%lld%c",a[q1.front()], i==n?'\n':' '); //k的时候就输出队头
}
}
int main()
{
scanf("%lld%lld",&n,&k);
k = min(k,n);
rep(i,1,n) scanf("%lld",&a[i]);
init();
solve();
return 0;
}