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

滑动窗口(Sliding Window)是算法面试和实际开发中最常见的技巧之一,尤其在数组字符串问题中。它能把暴力 O(n²) 降到 O(n)。

下面从最基础开始,用 Python 一步步讲解,适合初学者到中级开发者复习。

1. 滑动窗口核心思想(一句话记住)

两个指针(left 和 right)维护一个连续窗口,根据条件动态扩大收缩窗口,只遍历一次数组

两大类:

  • 固定长度窗口:窗口大小固定(如 k),只滑动
  • 可变长度窗口:窗口大小动态变化,根据条件收缩 left

2. 固定长度滑动窗口模板(最简单)

def fixed_window(nums: list[int], k: int) -> int:
    if len(nums) < k:
        return 0  # 或其他边界值

    # 初始化第一个窗口 [0, k-1]
    window_sum = sum(nums[:k])          # 当前窗口和
    max_sum = window_sum                # 记录最大值(或最小、计数等)

    # 从第 k 个元素开始滑动
    for right in range(k, len(nums)):
        # 窗口右移:减去最左边 + 加上新右边
        window_sum = window_sum - nums[right - k] + nums[right]
        max_sum = max(max_sum, window_sum)

    return max_sum

经典例题:LeetCode 643. 子数组最大平均数 I(固定窗口 k)

def findMaxAverage(nums: list[int], k: int) -> float:
    current = sum(nums[:k])
    max_sum = current

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

    return max_sum / k

3. 可变长度滑动窗口模板(最常用)

def variable_window(s: str) -> int:
    # 记录窗口内某种状态(如字符出现次数)
    count = {}                      # 哈希表 / Counter
    left = 0
    max_len = 0

    for right in range(len(s)):
        # 1. 右指针进窗口
        count[s[right]] = count.get(s[right], 0) + 1

        # 2. 判断是否非法 → while 收缩 left
        while count.get(s[right], 0) > 1:   # 条件:不允许重复字符
            count[s[left]] -= 1
            if count[s[left]] == 0:
                del count[s[left]]
            left += 1

        # 3. 此时窗口 [left, right] 合法,更新答案
        max_len = max(max_len, right - left + 1)

    return max_len

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

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

    char_index = {}         # 记录字符最后出现的位置(更高效写法)
    left = 0
    max_len = 0

    for right in range(len(s)):
        if s[right] in char_index and char_index[s[right]] >= left:
            # 发现重复,且重复位置在当前窗口内 → 移动 left
            left = char_index[s[right]] + 1

        char_index[s[right]] = right
        max_len = max(max_len, right - left + 1)

    return max_len

4. 常见滑动窗口变种模板对比(一图秒懂)

类型窗口大小移动方式典型题目(LeetCode)时间复杂度
固定窗口固定 k每次只移动 right 和 left=k步643、209(变形)、1004O(n)
可变窗口 – 最长尽量大right 扩张,left 收缩到合法3、424、567、76(最小覆盖子串)O(n)
可变窗口 – 最短尽量小right 扩张到合法,left 收缩209(长度最小的子数组)、76(最小覆盖子串)O(n)
最多允许 k 个不同动态记录不同字符数340、159、904O(n)
最多 k 次替换动态记录需要替换的次数424(最长重复字符替换)、1004O(n)
滑动窗口最大值固定 k单调队列维护最大值239O(n)

5. 初学者练习推荐顺序(强烈建议按顺序刷)

    1. Maximum Average Subarray I(固定窗口入门)
    1. Minimum Size Subarray Sum(最短子数组)
  1. 3. Longest Substring Without Repeating Characters(最经典)
    1. Permutation in String(固定长度 + 计数)
    1. Longest Repeating Character Replacement(k 次替换)
    1. Minimum Window Substring(最小覆盖子串,难度较高)
    1. Sliding Window Maximum(单调队列)

6. 写滑动窗口时最容易犯的 5 个错(避坑指南)

  • 忘记 left 初始化为 0
  • while 条件写成 if(导致窗口不完全收缩)
  • 收缩 left 后没有更新状态(如 count[left] -=1)
  • right – left + 1 写成 right – left(少 1)
  • 边界情况:空字符串、k > len(nums)、所有元素相同

一句话总结:

滑动窗口 = 两个指针 + 一段状态 + while 收缩 + 更新答案

如果你现在能手写上面 LeetCode 3 和 643 的代码,滑动窗口就基本入门了。

想针对某个具体题目(如 239、76、1004)要详细代码 + 思路吗?或者想看某个变种的完整模板?直接告诉我~

文章已创建 3996

发表回复

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

相关文章

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

返回顶部