# 一首诗让你把滑动窗口算法变成默写题

参考之前「二分搜索框架详解」中的打油诗,本文再次以一首诗来解释滑动窗口:

img

本文着重解决最难掌握的双指针技巧:滑动窗口技巧。总结出一套框架,可以保你闭着眼睛都能写出正确的解法。

说起滑动窗口算法,很多读者都会头疼。这个算法技巧的思路非常简单,就是维护一个窗口,不断滑动,然后更新答案。LeetCode 上起码有 10 道运用滑动窗口算法的题目,难度都是中等和困难。该算法的大致逻辑如下:

int left = 0, right = 0;

while (right < s.size()) {`
    // 增大窗口
    window.add(s[right]);
    right++;

    while (window needs shrink) {
        // 缩小窗口
        window.remove(s[left]);
        left++;
    }
}

这个算法的时间复杂度是 O(N) ,比字符串暴力算法要高效的多。

其实困扰大家的不是算法思路,而是各种细节问题。比如说如何向窗口中添加新元素,如何缩小窗口,在窗口滑动的哪个阶段更新结果。即便你明白了这些细节,也容易出 bug,找 bug 还不知道怎么找,真的挺让人心烦的。

所以今天总结一套滑动窗口算法的代码框架,我连哪里做输出 debug 都写好了,以后遇到相关问题,你就默写出来修改:

/* 滑动窗口算法框架 */
void slidingWindow(string s, string t) {
    unordered_map<char, int> need, window;
    for (char c : t) need[c]++;

    int left = 0, right = 0;
    int valid = 0; 
    while (right < s.size()) {
        // c 是将移入窗口的字符
        char c = s[right];
        // 右移窗口
        right++;
        // 进行窗口内数据的一系列更新
        ...

        /*** debug 输出的位置 ***/
        printf("window: [%d, %d)\n", left, right);
        /********************/

        // 判断左侧窗口是否要收缩
        while (window needs shrink) {
            // d 是将移出窗口的字符
            char d = s[left];
            // 左移窗口
            left++;
            // 进行窗口内数据的一系列更新
            ...
        }
    }
}

其中两处 ... 表示更新窗口数据的地方,到时候你直接往里面填就完事了。

而且,这两个 ... 处的操作分别是右移和左移窗口更新操作,等会你就会发现他们的操作是完全对称的。