返回算法课程
数组技巧基础

滑动窗口Sliding Window

维护一个连续区间,让左右边界只向前移动,从而避免重复扫描。

25 分钟前置:数组与字符串 · 集合 · 双指针

01先从一个问题出发

连续听歌时,希望找到一段没有重复歌曲的最长歌单。在字符串中,这就是最长无重复字符子串。

一个具体的例子

abcabcbb 的最长无重复子串长度是 3。读到第二个 a 时,只需移走窗口左端的第一个 a,保留已经检查过的 bc。

02最直接的办法,为什么慢?

固定每个起点,向右扩展并用集合检查重复。

暴力 · O(n²)

相邻起点重复检查大量相同字符。在字符互不相同的最坏情形下,扫描次数是 n+(n−1)+…+1。

03一步步,推导出优化思路

1

发现重复工作

检查 abc 后,把起点移动到 b 时,又要重新扫描 bc。已有的信息本可以保留。

2

保存窗口中的信息

使用集合保存当前窗口内的字符。右端新字符到来时,可以平均 O(1) 判断是否重复。

3

只移走导致失效的部分

若新字符已在集合中,反复移走左端字符,直到不再重复,再加入新字符并更新答案。

贯穿算法的不变量

每次更新 best 时,窗口 [left, right] 中没有重复字符,集合恰好保存这个窗口的字符。

04让每一步,都看得见

试着先预测下一步,再点击「下一步」验证。变量、动画与代码会同步变化。

Sliding Window交互演示
STEP 01 / 33
a
0left
b
1
c
2
a
3
b
4
c
5
b
6
b
7

橙色:当前字符 · 绿色:当前窗口 · 淡色:窗口外

当前处理已处理 / 已确定未处理
01

维护一个没有重复字符的连续窗口。

sliding_window.py参考实现 · 当前第 2 行
正在载入代码编辑器…

动画展示参考实现的执行轨迹。切换语言时,当前操作会定位到对应代码行。

05复杂度,来自具体的工作量

时间复杂度
O(n)O(n)

虽然 while 写在 for 内,但 right 走 n 次,left 最多也走 n 次。每个字符最多入集合、出集合各一次;假设哈希操作平均 O(1),总时间 O(n)。

辅助空间
O(min(n,Σ))O(\min(n, |\Sigma|))

集合最多保存窗口内互不相同的字符,数量不超过字符串长度 n 和字符集大小 |Σ| 的较小值。JavaScript 示例另外把字符串展开为码点数组,占 O(n)。

拖动 n,看看增长速度

06看到什么,应该想到它?

关键词只是线索,继续检查适用条件

07这些细节,容易踩坑

01

收缩用 while,不一定只移一次

abba 在最后一个 b 到来时,要先移 a 再移 b,才能恢复无重复。

02

先恢复合法,再记录答案

包含重复字符的临时窗口不能用于更新最长长度。

03

不是所有连续问题都适用

含负数的子数组和不具备简单单调收缩条件,常要使用前缀和 + 哈希表。

08把想法带进真实题目

先说出模式和适用条件,再开始写代码。

09不用背模板,回答这几个问题

01嵌套 while 为什么没有导致 O(n²)?

02窗口为 ab,读到第二个 b 后该怎么做?

03含负数数组的精确子数组和,首先考虑?

你已经走完了这次推导。

能用自己的话解释复杂度和不变量,再标记为掌握。

把知识连起来