Sliding Window
Time Limit: 12000MS | Memory Limit: 65536K | |
Total Submissions: 30677 | Accepted: 9159 | |
Case Time Limit: 5000MS |
Description
An array of size
n ≤ 10
6 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.
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个元素,窗口每次移动一个位置,问每次移动后窗口里的最大和最小的元素各是什么。
思路:维护最大长度为k的一个递减单调队列和一个递增单调队列。以递减单调队列为例:它的头元素一直是队列当中的最大值,而且队列中的值是按照递减的顺序排列的。我们可以从队列的末尾插入一个元素,可以从队列的两端删除元素。
插入操作:在插入元素v的时候,要将队尾的元素和v比较,如果队尾的元素不大于v,则删除队尾的元素,然后继续将新的队尾的元素与v比较,直到队尾的元素大于v,这个时候我们才将v插入到队尾。(确定元素的插入位置时可以用二分优化)
删除队首元素操作:因为窗口的size为k,当队列中元素数量多于k时,则删去对首元素。
单调队列与队列唯一的不同就在于它不仅要保存元素的值,而且要保存元素的索引(当然在实际应用中我们可以只需要保存索引,而通过索引间接找到当前索引的值)
同样的代码用G++提交TLE,C++提交AC。。。。
AC代码:
#include <cstring> #include <string> #include <cstdio> #include <algorithm> #include <queue> #include <cmath> #include <vector> #include <cstdlib> #include <iostream> using namespace std; const int maxn=1000005; int n,k,first,last; int sequence[maxn]; //保存原始序列 int max_ans[maxn]; //保存每插入一个元素,递减单调队列中的最大值 int min_ans[maxn]; //保存每插入一个元素,递增单调队列中的最小值 int index[maxn]; //保存单调队列中每个元素在原始序列中的下标 void decrease() //维护单调递减队列 { memset(index,0,sizeof(index)); last=first=1; index[last++]=1; max_ans[1]=sequence[1]; for(int i=2;i<=n;i++) { while(first<last&&sequence[index[last-1]]<sequence[i]) //将要插入的元素与队尾元素比较 last--; index[last++]=i; //插入队尾元素 if(index[first]<i-k+1) first++; //删除队首元素 max_ans[i]=sequence[index[first]]; //保存当前的队列中的最大值 } } void increase() //维护单调递增队列 { memset(index,0,sizeof(index)); last=first=1; index[last++]=1; min_ans[1]=sequence[1]; for(int i=2;i<=n;i++) { while(first<last&&sequence[index[last-1]]>sequence[i]) last--; index[last++]=i; if(index[first]<i-k+1) first++; min_ans[i]=sequence[index[first]]; } } int main() { scanf("%d%d",&n,&k); for(int i=1;i<=n;i++) scanf("%d",&sequence[i]); decrease(); increase(); for(int i=k;i<=n;i++) printf("%d ",min_ans[i]); printf("\n"); for(int i=k;i<=n;i++) printf("%d ",max_ans[i]); printf("\n"); return 0; }