滑动窗口算法学习之旅

918 阅读1分钟

「这是我参与11月更文挑战的第2天,活动详情查看:2021最后一次更文挑战」。

一、滑动窗口是什么?

滑动窗口(SlidingWindow)是一种想象出来的数据结构,滑动窗口有左边界L和右边界R。在数组或者字符串或者一个序列上,记为S,窗口就是S[L..R]这一部分,L往右滑意味着一个样本出了窗口,R往右滑意味着一个样本进了窗口,L和R都只能往右滑。

二、滑动窗口能做什么?

窗口不管L还是R滑动之后,都会让窗口呈现新状况,如何能够更快的得到窗口当前状况下的最大值和最小值?最好平均下来复杂度能够做到O(1)。

利用单调双端队列!不了解什么是双端队列,可以参考这篇文章

三、滑动窗口实现思路

image.png

四、滑动窗口题目

滑动窗口实现窗口内最大值

假设一个固定大小为W的窗口,依次划过arr,
返回每一次滑出状况的最大值
例如,arr = [4,3,5,4,3,3,6,7], W = 3
返回:[5,5,5,4,6,7]

image.png

暴力实现

public static int[] right(int[] arr, int w) {
    if (arr == null || w < 1 || arr.length < w) {
        return null;
    }
    int N = arr.length;
    int L = 0;
    int R = w - 1;
    int[] ans = new int[N - w + 1];
    int index = 0;
    while (R < N) {
        int max = arr[L];
        for (int i = L + 1; i <= R; i++) {
            max = Math.max(max, arr[i]);
        }
        ans[index++] = max;
        R++;
        L++;
    }
    return ans;
}

利用滑动窗口实现

// 利用滑动窗口,双端队列
public static int[] getMaxWindow(int[] arr, int w) {
    if (arr == null || w < 1 || arr.length < w) {
        return null;
    }
    LinkedList<Integer> queueMax = new LinkedList<>();
    int[] res = new int[arr.length - w + 1];
    int index = 0;
    for (int R = 0; R < arr.length; R++) {
        while (!queueMax.isEmpty() && arr[queueMax.peekLast()] <= arr[R]) {
            queueMax.pollLast();
        }
        queueMax.addLast(R);
        // 窗口过期下标
        if (queueMax.peekFirst() == R - w) {
            queueMax.pollFirst();
        }
        // 窗口预热,达到窗口大小时收集答案
        // 是否现在形成了正常窗口,窗口在未形成时,窗口属于培养期,不需要收集答案
        if (R >= w - 1) {
            res[index++] = arr[queueMax.peekFirst()];
        }
    }
    return res;
}

test

public static void main(String[] args) {
    int[] arr = {4, 3, 5, 4, 3, 3, 6, 7};
    int w = 3;
    System.out.println(Arrays.toString(right(arr, w)));
    System.out.println(Arrays.toString(getMaxWindow(arr, w)));
}