Appearance
滑动窗口法是一种常用且有效的算法技巧,特别适用于处理数组或字符串的连续子序列问题,我们来系统地梳理一下:
- 滑动窗口的基本概念
滑动窗口通常由两个指针定义一个窗口,这个窗口在数组或字符串上"滑动",窗口的大小可以是固定的,也可以是可变的。
- 滑动窗口的类型
- 固定大小的窗口
- 可变大小的窗口
- 滑动窗口的基本操作步骤
- 初始化窗口的左右边界(通常左右指针都在起始位置)
- 右指针向右移动,扩大窗口
- 当窗口满足特定条件时,左指针向右移动,缩小窗口
- 在这个过程中更新结果
- 固定大小窗口示例
问题:给定一个数组,计算所有长度为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
- 可变大小窗口示例
问题:找到字符串中包含所有给定字符的最小子串。
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]
- 滑动窗口的关键点
- 窗口的定义:明确窗口包含什么,代表什么
- 窗口的移动:何时扩大,何时缩小
- 更新逻辑:在窗口移动过程中如何更新结果
- 结果的维护:如何在整个过程中维护最优结果
- 常见的滑动窗口应用场景
- 子数组/子串问题
- 字符串的排列/组合问题
- 最长/最短满足条件的子数组/子串
- 求解数组/字符串中的最大/最小值问题
- 滑动窗口的优化技巧
- 使用哈希表或数组来存储窗口中的元素频率
- 使用双指针技巧来控制窗口的大小
- 在合适的时候使用提前返回来优化性能
- 实现滑动窗口的注意事项
- 正确初始化窗口和相关变量
- 仔细处理边界条件
- 确保窗口的扩大和缩小逻辑正确
- 在循环中正确更新结果
滑动窗口法的核心在于将暴力解法中的嵌套循环优化为单循环,通常可以将时间复杂度从 O(n^2) 优化到 O(n)。