1. 程式人生 > >POJ-2823-Sliding Window (單調佇列)

POJ-2823-Sliding Window (單調佇列)

原題連結
http://poj.org/problem?id=2823
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.
在這裡插入圖片描述


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
題意:
有n個數字組成的序列,有一個長度為k個視窗,從第一個一直滑動到最後一個,美妙滑動一次,每次滑動向後一個,每滑動一次就輸出窗口裡的數列的最小值和最大值。具體格式見樣例。
題解:
這道題目可以利用單調佇列,利用陣列記錄當前視窗的最大(小)值。
以找最小值舉例說明:
滑動視窗時,插入元素:刪除掉所有的所有比插入元素大的數值,程式碼裡其實就是將佇列q的右端點向左移,直到有比 插入元素小的時候插入。
如何實現視窗移動,並且保持佇列單調呢?
如果隊首元素的位置小於視窗的左界,則刪除,其他的不用管,因為最終輸出的時隊首元素,在隊首其後的元素對其不產生影響,並且如果在之後的移動中,之前未刪除的不在視窗的元素也會被刪除的。
(更多細節見程式碼,請讀者細細體會)

注意:這道題目耗時比較長,用cin,cout輸入輸出會超時

附上AC程式碼:

#include <iostream>
#include <cstdio>
using namespace std;
const int MAXN=1e6+5;
int a[MAXN],q[MAXN],n,k;
void workmin()
{
    int l=1,r=0,i=0;
    for(; i<k-1; i++)//初始化隊前k-1個元素
    {
        while(l<=r&&a[q[r]]>a[i]) r--;//當左端點小於右端點並且刪除掉比插入元素大的隊尾元素
        q[++r]=i;//插入輸入元素
    }
    for(; i<n; i++)//視窗移動
    {
        if(q[l]<=i-k) l++;//刪除不在視窗的隊首元素
        while(l<=r&&a[q[r]]>a[i]) r--;//含義同上,實現視窗移動
        q[++r]=i;
        printf("%d ",a[q[l]]);//輸出最小值
    }
    printf("\n");
}
void workmax()
{
    int l=1,r=0,i=0;
    for(; i<k-1; i++)//初始化隊的前k-1個元素
    {
        while(l<=r&&a[q[r]]<a[i]) r--;//左端點小於右端點,並且刪除隊尾比插入元素小的元素實現單調遞減
        q[++r]=i;//插入元素
    }
    for(; i<n; i++)
    {
        if(q[l]<=i-k) l++;//不在視窗內的都刪除
        while(l<=r&&a[q[r]]<a[i]) r--;
        q[++r]=i;
        printf("%d ",a[q[l]]);//輸出最大值printf
    }
    printf("\n");
}
int main()
{
    while(scanf("%d%d",&n,&k)!=EOF)
    {
        for(int i=0; i<n; i++)
            scanf("%d",a+i);
        workmin();
        workmax();
    }
    return 0;
}

歡迎評論!