滑动窗口介绍

示例练习>>>

滑动窗口一般用于操作字符串和数组,他是在一个特定大小的字符串和数组上进行操作,而不是直接操作整个字符串,这样就降低了操作的复杂度,也降低循环嵌套的深度。使用滑动窗口的时候一般使用两个指针,一个是左指针 left ,一个是右指针 right ,分别表示窗口的左边界和右边界,滑动的时候只需要关心窗口内的元素即可。滑动窗口只能朝一个方向滑,并且只能前进不能后退,一般情况下习惯从左往右滑动。

滑动窗口常见的有以下几类:

1,大小可变窗口:顾名思义就是窗口的大小是可变的,有可能增大,也有可能减小。他的实现原理是左指针先不动,右指针往右滑动如果是求最小值,右指针滑动的目的是先找到满足条件的解,找到之后右指针就不在动,然后左指针往右滑动,左指针往右滑动的目的是找到最优解……,一直重复上面的过程。如果是求最大值,右指针滑动的目的是满足条件之后先找到不满足条件的解,找到之后右指针就不在动,然后左指针往右滑动,左指针往右滑动的目的也是找出最优解……,一直重复上面的过程。

2,固定窗口:就是窗口的大小达到一定程度之后,窗口的大小就不在变化了。他的实现原理是刚开始的时候左指针不动,右指针往右移,当窗口长度达到固定大小之后左指针和右指针同时往右移动。

3,只增不减窗口:通过名字我们就知道,窗口的大小只能增加不能减小,这个一般用于求最大值的,他的实现原理是左指针先不动,右指针往右滑动,记录满足条件的最大值,当不满足条件的时候,左指针在往右移动一步,前面增加一步后面又减小一步相当于窗口大小没变,他的目的是始终保证窗口大小是满足条件的最大长度。

大小可变窗口

大小可变窗口的解题步骤如下:

1,声明两个变量 leftright ,分别表示窗口的左边界和右边界,一般使闭区间 [left,right] ,初始的时候都是 0
​2,如果是求最小值,左指针先不动,滑动右指针扩大窗口来找出满足条件的解,当窗口满足条件之后,右指针不在滑动,然后滑动左指针来缩小窗口找出最优解。
​3,如果是求最大值,也是左指针先不动,滑动右指针在满足条件的情况下继续滑动,直到不满足条件为止,然后右指针不在滑动,接着滑动左指针来找满足条件的解。
​4,重复上面的 23 直到右指针走到序列的末尾,不能在移动为止。

根据上面的步骤我们可以整理一个模板出来。

public int slidingWindow(String s) {
    // 记录结果的参数,一般是最大值或者最小值。
    int res = 0;

    // 窗口集合,记录窗口中的元素,这个可以是数组,list或者map都可以,
    // 也可以是个具体的数值,比如用来记录窗口中元素的和。
    window

    // 闭区间[left,right]
    int left = 0;// 窗口的左边界。
    int right = 0;// 窗口的右边界。
    while (right < s.length()) {
        // 这里可以先删除在添加,也可以先添加在删除,需要根据不同的题做不同的调整。
        // 这里把右指针的元素添加到窗口中。
        window.add(s.charAt(right));
        while ("窗口是否满足条件") {
            // 移除窗口左边的元素。
            window.remove(s.charAt(left));
            left++;// 缩小窗口,右指针不动,窗口左边界往右移。
        }
        // 更新结果,取最大值或最小值,或者是其他操作。
        res = Math.max(res, window.size());
        // 右指针始终往右移。
        right++;
    }
    return res;
}

固定窗口

固定窗口并不是一开始就是固定的,而是右指针先动,左指针不动,当窗口的长度达到一个固定的长度之后,左指针和右指针在同时往右移,固定窗口的解题步骤如下:

1,声明两个变量 leftright ,分别表示窗口的左边界和右边界 。
2,右指针始终往右滑动,当窗口达到固定长度之后,每次左指针和右指针在同时往右滑动。

这个相对来说就比较简单了,根据上面的步骤我们也可以整理一个模板来。

public int slidingWindow(String s, int k) {
    int res = 0;// 记录结果的参数。
    // 这里可以先计算字符串 s 的前 k 个字符,也可以在while循环中计算。
    int left = 0;// 窗口的左边界。
    int right = 0;// 窗口的右边界。
    while (right < s.length()) {
        // 这里会进行一些逻辑操作,不在是while循环,而是改成if,
        // 如果窗口长度等于k,然后进行一些操作。
        if (right - left + 1 == k) {
            // 其他的一些逻辑操作,操作完之后要移除窗口的左边界元素。
            window.remove(s.charAt(left));
            left++;// 只有在窗口长度等于 k 的时候,左指针才往右滑动。
        }
        // 更新结果,或者是其他操作。
        res = Math.max(res, window.size());
        right++; // 右指针始终往右移。
    }
    return res;
}

只增不减窗口

只增不减窗口不像第一种一会变大一会变小,也不像第二种当增大到一定程度之后窗口长度就不在变了,这种只增不减窗口的长度只会增加不会减小。其实他和第二种固定窗口有点像,只不过在窗口逻辑判断的时候会多一个变量,并且这个变量一般情况下都是增加的,所以判断的时候会导致窗口只增不减,一般主要是求最大长度或最大值的,其实模板也都差不多,大致看下。

public int slidingWindow(String s, int k) {
    int max = 0;// 记录结果的参数。
    int left = 0;// 窗口的左边界。
    int right = 0;// 窗口的右边界。
    while (right < s.length()) {
        // 一些其他逻辑。
        // 这里因为max是增加的,所以窗口只会增大不会变小。
        // 注意这里是if语句,不是while循环。
        if (right - left + 1 >= k + max) {
            // 其他的一些逻辑操作,操作完之后要移除窗口左边元素。
            window.remove(s.charAt(left));
            left++;// 滑动左指针。
        } else {
            // 更新结果,或者是其他操作。
            max = Math.max(max, window.size());
        }
        right++; // 右指针始终往右移。
    }
    return max;
}

信奥赛编程(刷题请进)>>>

经过两年的打磨,我的新作《算法秘籍》已经出版,有需要的可以点击购买。也可以点击 内容介绍 查看详情。