深入理解滑动窗口算法:使用 C 语言寻找最小值

        滑动窗口是一种高效的算法技术,广泛用于处理数组和字符串相关问题,它通过动态维护一个“窗口”,迅速计算出所需的信息。在本文中,我们将实现一个具体的滑动窗口例子,寻找一个整数数组中每个长度为 k 的子数组(窗口)中的最小值,并详细解释代码实现。

算法概述

        我们将使用一个双端队列(deque)来维护窗口中元素的索引,并确定每个窗口的最小值。这个方法的关键是利用单调队列的性质:在每个时刻,队列的头元素始终是窗口内的最小值。

#include 
#define N 1000010

//数组q作为双端队列,存储窗口里维护的元素索引,里面存储的索引数字是单调的
//数组a存储整个序列的数字
int q[N], a[N];

int main() {
    //输入n个数,滑动窗口大小为k
    int n, k;
    scanf("%d%d", &n, &k);

    for (int i = 0; i < n; i++) {
        scanf("%d", &a[i]);
    }

    //hh表示队列头 tt表示队列尾
    int hh = 0, tt = -1;

    //第一次遍历:求每个窗口的最小值
    //i表示窗口的右边界
    for (int i = 0; i < n; i++) {
        //队头超出窗口范围,则弹出
        //窗口范围应为 [i-k+1,i]
        if (hh <= tt && q[hh] < i - k + 1) {
            hh++;
        }

        //保持队列单调性,将较大的值弹出
        while (hh <= tt && a[q[tt]] >= a[i]) {
            tt--;
        }

        //当前元素索引进入队列
        q[++tt] = i;

        //如果窗口已经形成,输出窗口的最小值
        if (i + 1 >= k) {
            printf("%d ", a[q[hh]]);
        }
    }

    printf("\n");
    hh = 0, tt = -1;

    //第二次遍历:求每个窗口的最大值
    for (int i = 0; i < n; i++) {
        //队头超出窗口范围,则弹出
        if (hh <= tt && q[hh] < i - k + 1) {
            hh++;
        }
        //保持队列单调性,将较小的值弹出
        while (hh <= tt && a[q[tt]] <= a[i]) {
            tt--;
        }
        q[++tt] = i;

        //如果窗口已经形成,输出窗口的最大值
        if (i + 1 >= k) {
            printf("%d ", a[q[hh]]);
        }
    }

    return 0;
}
代码解释
  1. 数据结构与初始化:

    • q[N]:用作双端队列,存储当前窗口内元素的索引,确保这些索引的对应值是单调的。
    • a[N]:存储输入的整数序列。
  2. 输入部分:

    • 从标准输入读取整数 n(数组大小)和 k(窗口大小)。
    • 读取 n 个整数到数组 a 中。
  3. 第一次遍历

    • 使用 hh 和 tt 维护队列的头尾。
    • 利用滑动窗口的特性,更新队列,保持单调性,确保 a[q[hh]] 始终是当前窗口的最小值。
    • 通过 if (i + 1 >= k) 确认窗口大小已经达到 k,然后输出最小值。
  4. 第二次遍历

    • 重复上述操作,只不过这次是为了输出每个窗口的最大值。
    • 修改了条件,保持单调性并输出当前窗口的最大值。
运行示例

假设输入为:


5 3
1 3 -1 -3 5

 

  • 这里 n=5k=3,数组 a 为 [1, 3, -1, -3, 5]

运行逻辑如下:

  1. 第一次遍历
    • 窗口 [1, 3, -1] 的最小值为 -1
    • 窗口 [3, -1, -3] 的最小值为 -3
    • 窗口 [-1, -3, 5] 的最小值为 -3
  2. 输出:

 

-1 -3 -3
  1. 第二次遍历
    • 窗口 [1, 3, -1] 的最大值为 3
    • 窗口 [3, -1, -3] 的最大值为 3
    • 窗口 [-1, -3, 5] 的最大值为 5

输出:

3 3 5

 

最后输出结果为:

-1 -3 -3
3 3 5

 

图解

窗口移动过程

 a = [1, 3, -1, -3, 5]

  1. 窗口 [1, 3, -1]:

 a = [1, 3, -1, -3, 5] -1 is the minimum in the window.

  1. 窗口 [3, -1, -3]:

 a = [1, 3, -1, -3, 5] -3 is the minimum in the window.

  1. 窗口 [-1, -3, 5]:

 a = [1, 3, -1, -3, 5] -3 is the minimum in the window.

 

 

你可能感兴趣的:(算法,数据结构)