滑动窗口

1. 关于常用方法的介绍,在一个区间内寻找最大值或者最小值。

题目链接:154. 滑动窗口 - AcWing题库

举例,在一个长度为s数组中,窗口的大小为k,窗口从最左侧开始进行移动,输出窗口中最大和最小的两个元素。

2. 思考,在窗口的移动过程中,不断有旧的元素消失,新的元素进来,即先进先出,符合队列的特征。

从暴力的角度来看,每个窗口中找一遍即可,然而当窗口过大,数组过长时,时间会超时。

3. 分析,数组如下:

4  3  8  7  5  6  , 窗口大小为3。

我们首先来寻找窗口中的最小值。

首先4进入窗口。

接着是3,可以思考一下这个时候。4已经在窗口中了,4 大于 3 ,如果3进入窗口,那么4是否还有存在的必要呢?就是3在4的后面进入,并且3小于4,那么在窗口的移动过程中,4一定会首先滑出窗口。而且,4也没有可能会被当做最小值进行输出,那么,我们可以选择将4扔出。

所以我们可以总结出一下规律,如果要进入的数字比在窗口中的数字要小,就需要将窗口中的这个数字扔出。

结合第二点中的队列特点,即在比较和扔出过后,要进入的数字一定比当前窗口中最近的数字大,所以说,这是一个单调递增的队列,当我们想要求取窗口中的最小值时,只需要判断在“合法”的情况下输出队头元素即可。

4. 接下来我们进行分析什么样的情况下合法。

  (1)不能是空队列。

  (2)我们从第一个元素开始进入,那么我们必须要最少总共进入过一个窗口后才可以进行输出,结合样例即在窗口到达4 3 8的时候才会进行输出。

  (3)我们的窗口在向前滑动,很可能队头却一直停留,因此,必须保证队头在窗口当中。

5. 具体的代码。

 //求最小值
    for (int i = 0; i < n; i ++)
    {
        // 防止溢出
        if (tt >= hh && (i - k) >= q[hh]) hh ++;
        
        while (tt >= hh && e[q[tt]] >= e[i]) tt --;
        q[++ tt] = i;
        
        if (i - k + 1 >= 0) printf("%d ", e[q[hh]]);
    }

 

6. 要寻找最大的元素时,同理,请稍微进行思考一些。

posted on 2023-07-05 14:09  481zch  阅读(39)  评论(0)    收藏  举报

导航