點擊打開鏈接 題目鏈接
Time Limit: 12000MS | Memory Limit: 65536K | |
Total Submissions: 40565 | Accepted: 11982 | |
Case Time Limit: 5000MS |
Description
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
Output
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的窗在整數數列上移動,求窗裏面所包含的數的最小值最大值。
單調隊列定義:
a)從隊頭到隊尾,元素在我們所關注的指標下是遞減的(嚴格遞減,而不是非遞增),比如查詢如果每次問的是窗口內的最小值,那麼隊列中元素從左至右就應該遞增,如果每次問的是窗口內的最大值,則應該遞減,依此類推。這是爲了保證每次查詢只需要取隊頭元素。
b)從隊頭到隊尾,元素對應的時刻(此題中是該元素在數列a中的下標)是遞增的,但不要求連續,這是爲了保證最左面的元素總是最先過期,且每當有新元素來臨的時候一定是插入隊尾。
代碼:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int que[1111111],num[1111111],maxn[1111111],minn[1111111],index[1111111];
int n,k;
void getmin()
{
int fr=1,ed=0,i;
for(i=0;i<k-1;i++)
{
while(fr<=ed&&que[ed]>=num[i])
ed--;
que[++ed]=num[i];
index[ed]=i;
}
for(;i<n;i++)
{
while(fr<=ed&&que[ed]>=num[i])
ed--;
que[++ed]=num[i];
index[ed]=i;
while(index[fr]<i-k+1)
{
fr++;
}
minn[i-k+1]=que[fr];
}
}
void getmax()
{
int fr=1,ed=0,i;
for(i=0;i<k-1;i++)
{
while(fr<=ed&&que[ed]<=num[i])
ed--;
que[++ed]=num[i];
index[ed]=i;
}
for(;i<n;i++)
{
while(fr<=ed&&que[ed]<=num[i])
ed--;
que[++ed]=num[i];
index[ed]=i;
while(index[fr]<i-k+1)
{
fr++;
}
maxn[i-k+1]=que[fr];
}
}
int main()
{
//freopen("acm.txt","r",stdin);
scanf("%d %d",&n,&k);
for(int i=0;i<n;i++)
{
scanf("%d",&num[i]);
}
getmin();
getmax();
for(int i=0;i<n-k+1;i++)
{
if(i<n-k)
printf("%d ",minn[i]);
else
printf("%d\n",minn[i]);
}
for(int i=0;i<n-k+1;i++)
{
if(i<n-k)
printf("%d ",maxn[i]);
else
printf("%d\n",maxn[i]);
}
return 0;
}