基础算法:滑动窗口_python版本

滑动窗口(Sliding Window) 是算法中非常常见且高频出现的一类技巧,尤其在处理连续子数组/子串相关问题时,几乎是“必备武器”。

它最核心的思想是:

通过维护一个固定长度动态长度的窗口,在数组/字符串上只向前滑动(不回溯),从而把暴力 O(n²) 降到 O(n) 或 O(n log n)。

滑动窗口的两种主要形态(Python实现角度)

类型窗口长度典型代表题时间复杂度核心维护什么?
固定长度窗口窗口大小固定长度为 k 的最大/最小子数组和O(n)窗口内元素和/计数/最大值等
动态长度窗口窗口大小可变最长无重复子串、最小覆盖子串O(n)满足/不满足条件的边界移动

下面分别给出两种最经典的写法模板 + 代表题目代码。

一、固定长度滑动窗口模板

def fixed_window(arr, k):
    if len(arr) < k:
        return None  # 或根据题目要求返回

    # 初始化第一个窗口 [0...k-1]
    window_sum = sum(arr[:k])          # 窗口内元素和(最常见)
    # window_max = max(arr[:k])        # 如果求最大值
    # window_count = Counter(arr[:k])  # 如果需要计数

    result = window_sum   # 或者其他统计量

    # 窗口向右滑动
    for i in range(k, len(arr)):
        # 移除左边界
        window_sum -= arr[i - k]
        # 加入右边界
        window_sum += arr[i]

        # 更新答案(根据题目要求)
        result = max(result, window_sum)   # 例如求最大和

    return result

经典例题
力扣 643. 子数组最大平均数 I(窗口大小为 k 的最大平均值)

def findMaxAverage(nums: List[int], k: int) -> float:
    if len(nums) < k:
        return 0.0

    window_sum = sum(nums[:k])
    max_sum = window_sum

    for i in range(k, len(nums)):
        window_sum = window_sum - nums[i - k] + nums[i]
        max_sum = max(max_sum, window_sum)

    return max_sum / k

二、动态长度滑动窗口模板(最经典写法)

def dynamic_window(s: str) -> int:
    # 记录窗口内字符出现的次数(或状态)
    window = {}           # 哈希表 / Counter
    left = 0
    ans = 0               # 记录最优答案

    for right in range(len(s)):
        # 1. 把右边界字符加入窗口
        c = s[right]
        window[c] = window.get(c, 0) + 1

        # 2. 判断是否需要收缩左边界(while 循环)
        while window.get(c, 0) > 1:   # 条件根据题目变化
            # 移除左边界字符
            d = s[left]
            window[d] -= 1
            if window[d] == 0:
                window.pop(d)
            left += 1

        # 3. 此时 [left, right] 是合法窗口
        ans = max(ans, right - left + 1)

    return ans

最经典例题
力扣 3. 无重复字符的最长子串

def lengthOfLongestSubstring(s: str) -> int:
    if not s:
        return 0

    window = {}           # char -> last index
    left = 0
    max_len = 0

    for right in range(len(s)):
        if s[right] in window and window[s[right]] >= left:
            # 发现重复,移动左指针到上一次出现位置的右边
            left = window[s[right]] + 1

        # 更新该字符最新出现位置
        window[s[right]] = right

        max_len = max(max_len, right - left + 1)

    return max_len

三、滑动窗口常见变形 & 模板总结(背下来很有用)

题目类型窗口移动条件(while 里写什么)记录什么答案推荐写法
最长无重复子串while s[right] in window and window[s[right]] >= leftright – left + 1记录最后出现位置
最小覆盖子串while 窗口已包含所有字符记录最小长度窗口记录有效次数
长度为 k 的最大和/最小和无需 while,固定移动 k 长度维护窗口和/最大值前缀和或直接累加
至多 k 个不同字符的最长子串while len(window) > kright – left + 1Counter 或 set
包含所有 T 中字符的最短子串while 有效字符数 == len(t)更新最小长度need, have 计数器

四、练习推荐顺序(强烈建议按这个顺序刷)

    1. 长度最小的子数组(和 ≥ target)
  1. 3. 无重复字符的最长子串
    1. 最小覆盖子串
    1. 找到字符串中所有字母异位词
    1. 字符串的排列
    1. 替换后的最长重复字符
    1. 最大连续1的个数 III(至多翻转 K 个 0)
    1. 滑动窗口最大值(使用双端队列)

五、快速记忆口诀

左指针不动则右移,右移必加入元素
条件不满足则左移,左移必移除元素
每次右指针移动都尝试更新答案
while 收缩左边界,直到条件重新满足

如果你现在想看某一道具体题目的完整代码(比如 76、239、424 等),或者想看双指针 + 滑动窗口的混合写法,可以直接告诉我题号或关键词,我给你写最清晰的 Python 版本。

你目前最想看哪一类滑动窗口的代码?

文章已创建 4758

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部