CHAPTER 03 · 区间建模

滑动窗口与前缀和

把子数组和子串问题转化为可维护的窗口或可快速查询的区间。

3 个知识小节7 道分层练习5–6 天 建议周期
展开本章目录
  1. 学习之前
  2. 1. 固定长度窗口
  3. 2. 可变窗口的扩张与收缩
  4. 3. 前缀和与历史状态索引
  5. 延伸阅读
  6. 分层练习
  7. 我的笔记
00

BEFORE LEARNING

先理解为什么学

子数组和子串题的核心是如何复用相邻区间的计算结果。窗口维护连续区间状态,前缀和把任意区间查询转成两个历史状态之差。

开始前应具备

  • 掌握左右指针
  • 能使用哈希表保存计数
  • 理解连续子数组与子序列的区别

完成本章后

  • 写出窗口扩张与收缩框架
  • 判断固定窗口和可变窗口
  • 使用前缀和处理区间统计
01

CORE LESSONS

知识讲义

01

LESSON

固定长度窗口

什么时候想到它?

题目要求所有长度恰好为 k 的连续区间,或模式串长度固定时使用。

窗口每向右移动一步,只加入一个新元素并移除一个旧元素。维护增量而不是重新统计整个区间,可把 O(nk) 降到 O(n)。

推导步骤

  1. 初始化第一个完整窗口
  2. 右端加入新元素
  3. 窗口超过 k 后移除左端
  4. 窗口长度为 k 时更新答案
思维模板 / 伪代码
for right in range(n):
  add(a[right])
  if right - left + 1 > k: remove(a[left]); left += 1
  if right - left + 1 == k: update()
02

LESSON

可变窗口的扩张与收缩

什么时候想到它?

寻找满足约束的最长或最短连续区间,且条件随窗口扩张具有可恢复的单调性时使用。

右指针负责探索新候选,左指针负责恢复合法性。最长问题通常在窗口合法时记录;最短问题通常在合法状态下持续收缩并记录。

推导步骤

  1. 右端元素进入并更新状态
  2. 在不合法或仍可缩小时移动左端
  3. 选择正确时机更新最优答案
  4. 明确空答案的返回值
思维模板 / 伪代码
for right in range(n):
  add(right)
  while need_shrink():
    update_if_minimum()
    remove(left); left += 1
  update_if_maximum()
03

LESSON

前缀和与历史状态索引

什么时候想到它?

需要统计任意连续区间的和、数量,尤其数组包含负数而滑动窗口失效时使用。

若 prefix[j] - prefix[i] = k,则只需在扫描到 j 时查找历史上是否出现 prefix[j] - k。哈希表保存历史前缀值的次数或最早位置。

推导步骤

  1. 定义 prefix 表示前多少个元素
  2. 把区间条件改写成两个前缀的关系
  3. 查询目标历史前缀
  4. 再记录当前前缀,注意初始前缀 0
思维模板 / 伪代码
count = {0: 1}
prefix = answer = 0
for value in a:
  prefix += value
  answer += count.get(prefix - k, 0)
  count[prefix] += 1
02

READING

延伸阅读

先读完本站讲义并尝试练习;遇到推导不清的地方,再回到原始教程深入阅读。

03

PRACTICE LADDER

按作用分层练习

题量由知识点决定,不再固定为 5 道。先完成“入门”和“模板”,再做变式与综合;挑战题可以留到复习阶段。

入门认识结构模板独立复现变式迁移条件综合组合技巧挑战延后突破
01

固定长度窗口

2 道 · 依次完成

LC 643入门简单

子数组最大平均数 I

Maximum Average Subarray I

为什么选:先掌握加入一个、移除一个的增量维护。

固定窗口建议 15 分钟
打开 LeetCode ↗
LC 438变式中等

找到字符串中所有字母异位词

Find All Anagrams

为什么选:固定窗口中维护字符频率差。

固定窗口建议 35 分钟
打开 LeetCode ↗
02

可变窗口的扩张与收缩

3 道 · 依次完成

LC 3模板中等

无重复字符的最长子串

Longest Substring

为什么选:建立字符重复时收缩左边界的标准流程。

可变窗口建议 30 分钟
打开 LeetCode ↗
LC 209变式中等

长度最小的子数组

Minimum Size Subarray Sum

为什么选:体会最短窗口必须在合法时持续收缩。

窗口收缩建议 30 分钟
打开 LeetCode ↗
LC 76挑战困难

最小覆盖子串

Minimum Window Substring

为什么选:同时维护需要字符、有效字符和最小答案。

窗口计数建议 60 分钟
打开 LeetCode ↗
03

前缀和与历史状态索引

2 道 · 依次完成

LC 560模板中等

和为 K 的子数组

Subarray Sum Equals K

为什么选:通过 prefix - k 查询历史前缀次数。

前缀和 + 哈希建议 35 分钟
打开 LeetCode ↗
LC 525综合中等

连续数组

Contiguous Array

为什么选:把 0 转成 -1 后将数量平衡转成前缀相等。

前缀状态建议 40 分钟
打开 LeetCode ↗
04

PERSONAL NOTEBOOK

我的学习笔记

我如何识别这个模式?今天卡在哪里?下次需要先检查什么?

笔记保存在当前浏览器