问题描述
滑动窗口是一种用于解决数组或字符串中子区间问题的有效算法技巧,尤其适用于需要处理连续区间的问题。它通过维护一个动态的窗口(通常由两个指针表示左右边界),在遍历过程中调整窗口的大小或位置,从而高效地解决问题。以下是滑动窗口的两种常见类型及Python实现示例:
一、滑动窗口的两种类型
-
固定大小的窗口
窗口长度固定,通过滑动窗口计算特定值(如最大值、平均值等)。 -
动态调整的窗口
窗口长度根据条件动态变化(如无重复字符的最长子串)。
二、固定大小窗口示例:连续子数组的最大平均值
问题:给定数组 nums
和整数 k
,找到长度等于 k
的连续子数组的最大平均值。
算法步骤
- 计算初始窗口的和。
- 滑动窗口,每次减去左端元素,加上右端新元素。
- 更新最大值。
Python代码
def find_max_average(nums, k):window_sum = sum(nums[:k])max_sum = window_sumfor i in range(k, len(nums)):window_sum += nums[i] - nums[i - k]max_sum = max(max_sum, window_sum)return max_sum / k# 示例
nums = [1, 12, -5, -6, 50, 3]
k = 4
print(find_max_average(nums, k)) # 输出 12.75(子数组 [12, -5, -6, 50])
三、动态窗口示例:无重复字符的最长子串
问题:给定字符串 s
,找到其中不含有重复字符的最长子串的长度。
算法步骤
- 使用左右指针定义窗口,用哈希表记录字符的最新位置。
- 右指针不断右移,若字符重复,更新左指针到重复位置的下一个。
- 更新最大窗口长度。
实现
def length_of_longest_substring(s):char_map = {} # 记录字符最后出现的位置left = max_len = 0for right, char in enumerate(s):if char in char_map and char_map[char] >= left:left = char_map[char] + 1 # 移动左指针避免重复char_map[char] = rightmax_len = max(max_len, right - left + 1)return max_len# 示例
s = "abcabcbb"
print(length_of_longest_substring(s)) # 输出 3("abc")
四、滑动窗口的适用场景
- 连续子数组/子串问题
如最大和、最小长度、平均值等。 - 需要高效遍历的区间问题
将时间复杂度从暴力法的 O(n²) 优化到 O(n)。 - 常见题目
- 最小覆盖子串(LeetCode 76)
- 长度最小的子数组(LeetCode 209)
- 字符串的排列(LeetCode 567)
关键点总结
- 双指针:滑动窗口通常由左右指针 (
left
,right
) 定义。 - 哈希表辅助:用于快速判断重复或统计字符频率。
- 边界条件:注意处理空输入或无效参数(如
k=0
)。