zoukankan      html  css  js  c++  java
  • POJ 2823 Sliding Window

    题目

    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 knumbers 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 positionMinimum valueMaximum 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

    题目大意

     

    给定一个数列,从左至右输出每个长度为m的数列段内的最小数和最大数。

    数列长度:N<=10^6,m<=N (以最大值为例)

    8 3

    1 3 -1 -3 5 3 6 7

    3 3 5 5 6 7

    分析

        首先我们在找f(i)时,当前前面已经找过了,重新找就会浪费时间,那么如何保存上一次的结果呢?

        所以我们要用到单调队列

        

        使用单调队列就涉及到去头和删尾:

        单调队列具有队列内所有元素不是单调递增就是单调递减的性质,所以每次的最小(最大)值一定会在队首

        程序实现过程中先将前k个元素入队,此后每次在队尾加入a[k+1...n],在插入元素中同时进行以下操作:

    1. 将队尾所有大于或小于a[i]的值弹出队列
    2. 插入a[i]到队尾
    3. 判断队首元素位置是否超出i-k

        每次取对头输出就好了

    代码

     1 #include<iostream>
     2 #include<queue>
     3 #include<cstdio>
     4 #define N 1000000
     5 using namespace std;
     6 int a[N+1];
     7 int q[N+1];
     8 int qq[N+1];
     9 int main ()
    10 {
    11     int n,m;
    12     scanf("%d %d",&n,&m);
    13     for (int i=1;i<=n;i++)
    14        scanf("%d",&a[i]);
    15     q[1]=1;
    16     if (m==1) cout<<a[q[1]]<<" ";  //特判
    17     int h=1,t=1;
    18     for (int i=2;i<=n;i++)  //找最小
    19     {
    20         while (h<=t&&a[q[t]]>=a[i]) t--;  //当我加进来的数比队位小,那么就要插队向前找 
    21         q[++t]=i;   //存放下标
    22         while (i-q[h]>=m) h++;  //当超出我当前的范围值时,头指针后移
    23         if (i>=m) printf("%d ",a[q[h]]);
    24     }
    25     cout<<endl;
    26     qq[1]=1;
    27     if (m==1) cout<<a[qq[1]]<<" ";
    28     h=1,t=1;
    29     for (int i=2;i<=n;i++)
    30     {
    31         while (h<=t&&a[qq[t]]<=a[i]) t--;
    32         qq[++t]=i;
    33         while (i-qq[h]>=m) h++;
    34         if (i>=m) printf("%d ",a[qq[h]]);
    35     }
    为何要逼自己长大,去闯不该闯的荒唐
  • 相关阅读:
    RabbitMQ教程
    设置文件夹共享及所有访问权限
    一键操作IIS
    C#操作IIS服务
    【01】浅谈HTTP在WebApi开发中的运用
    Socket通信原理
    C# 通过JObject解析json对象
    MVC小知识整理
    Global.asax文件的作用
    iOS开发日记9-终端命令
  • 原文地址:https://www.cnblogs.com/zjzjzj/p/10224952.html
Copyright © 2011-2022 走看看