Skip to content

滑动窗口法是一种常用且有效的算法技巧,特别适用于处理数组或字符串的连续子序列问题,我们来系统地梳理一下:

  1. 滑动窗口的基本概念

滑动窗口通常由两个指针定义一个窗口,这个窗口在数组或字符串上"滑动",窗口的大小可以是固定的,也可以是可变的。

  1. 滑动窗口的类型
  • 固定大小的窗口
  • 可变大小的窗口
  1. 滑动窗口的基本操作步骤
  • 初始化窗口的左右边界(通常左右指针都在起始位置)
  • 右指针向右移动,扩大窗口
  • 当窗口满足特定条件时,左指针向右移动,缩小窗口
  • 在这个过程中更新结果
  1. 固定大小窗口示例

问题:给定一个数组,计算所有长度为k的连续子数组的最大平均值。

python
from typing import List


def find_max_average(nums: List[int], k: int) -> float:
    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
  1. 可变大小窗口示例

问题:找到字符串中包含所有给定字符的最小子串。

python
from collections import Counter


def min_window(s: str, t: str):
    need = Counter(t)
    window = Counter()
    left, right = 0, 0
    valid = 0
    start, min_len = 0, float('inf')

    while right < len(s):
        c = s[right]
        right += 1
        if c in need:
            window[c] += 1
            if window[c] == need[c]:
                valid += 1
        
        while valid == len(need):
            if right - left < min_len:
                start = left
                min_len = right - left
            d = s[left]
            left += 1
            if d in need:
                if window[d] == need[d]:
                    valid -= 1
                window[d] -= 1

    return "" if min_len == float('inf') else s[start:start+min_len]
  1. 滑动窗口的关键点
  • 窗口的定义:明确窗口包含什么,代表什么
  • 窗口的移动:何时扩大,何时缩小
  • 更新逻辑:在窗口移动过程中如何更新结果
  • 结果的维护:如何在整个过程中维护最优结果
  1. 常见的滑动窗口应用场景
  • 子数组/子串问题
  • 字符串的排列/组合问题
  • 最长/最短满足条件的子数组/子串
  • 求解数组/字符串中的最大/最小值问题
  1. 滑动窗口的优化技巧
  • 使用哈希表或数组来存储窗口中的元素频率
  • 使用双指针技巧来控制窗口的大小
  • 在合适的时候使用提前返回来优化性能
  1. 实现滑动窗口的注意事项
  • 正确初始化窗口和相关变量
  • 仔细处理边界条件
  • 确保窗口的扩大和缩小逻辑正确
  • 在循环中正确更新结果

滑动窗口法的核心在于将暴力解法中的嵌套循环优化为单循环,通常可以将时间复杂度从 O(n^2) 优化到 O(n)。