算法学习|滑动窗口问题

问题描述

滑动窗口用于解决数组或字符串中子区间问题,尤其适用于需要处理连续区间的问题。
通过维护一个动态的窗口(通常由两个指针表示左右边界),在遍历过程中调整窗口的大小或位置,从而高效地解决问题。


一、滑动窗口的两种类型

  1. 固定大小的窗口
    窗口长度固定,通过滑动窗口计算特定值(如最大值、平均值等)。

  2. 动态调整的窗口
    窗口长度根据条件动态变化(如无重复字符的最长子串)。


二、固定大小窗口示例:连续子数组的最大平均值

问题:给定数组 nums 和整数 k,找到长度等于 k 的连续子数组的最大平均值。

算法步骤

  1. 计算初始窗口的和。
  2. 滑动窗口,每次减去左端元素,加上右端新元素。
  3. 更新最大值。
def find_max_average(nums, k):
    window_sum = sum(nums[:k])
    max_sum = window_sum
    for 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,找到其中不含有重复字符的最长子串的长度。

算法步骤

  1. 使用左右指针定义窗口,用哈希表记录字符的最新位置。
  2. 右指针不断右移,若字符重复,更新左指针到重复位置的下一个。
  3. 更新最大窗口长度。

实现

def length_of_longest_substring(s):
    char_map = {}  # 记录字符最后出现的位置
    left = max_len = 0
    for right, char in enumerate(s):
        if char in char_map and char_map[char] >= left:
            left = char_map[char] + 1  # 移动左指针避免重复
        char_map[char] = right
        max_len = max(max_len, right - left + 1)
    return max_len

# 示例
s = "abcabcbb"
print(length_of_longest_substring(s))  # 输出 3("abc")

四、滑动窗口的适用场景

  1. 连续子数组/子串问题
    如最大和、最小长度、平均值等。
  2. 需要高效遍历的区间问题
    将时间复杂度从暴力法的 O(n²) 优化到 O(n)。
  3. 常见题目
    • 最小覆盖子串(LeetCode 76)
    • 长度最小的子数组(LeetCode 209)
    • 字符串的排列(LeetCode 567)

关键点总结

  • 双指针:滑动窗口通常由左右指针 (left, right) 定义。
  • 哈希表辅助:用于快速判断重复或统计字符频率。
  • 边界条件:注意处理空输入或无效参数(如 k=0)。
posted @ 2025-03-16 16:28  lumiere_cloud  阅读(133)  评论(0)    收藏  举报