
⚡ CYBER_PROFILE ⚡
/// SYSTEM READY ///
WARNING : DETECTING HIGH ENERGY
🌊 🌉 🌊 心手合一 · 水到渠成

|------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------|
| >>> ACCESS TERMINAL <<< ||
| 🦾 作者主页 | 🔥 C++初阶 |
| 💾C++进阶 | 📡 代码仓库 |
Running Process: 100% | Latency: 0ms
索引与导读
- 前言
-
- 一、什么是滑动窗口?
-
- [1.1 核心机制:左右边界的律动](#1.1 核心机制:左右边界的律动)
- [1.2 🖼️ 滑动窗口动态演示:寻找和为 7 的连续子数组](#1.2 🖼️ 滑动窗口动态演示:寻找和为 7 的连续子数组)
- 二、滑动窗口的两大分类
-
- [2.1 固定窗口](#2.1 固定窗口)
- [2.2 可变窗口](#2.2 可变窗口)
- 三、滑动窗口的通用模板
-
- [3.1 解题思路模板](#3.1 解题思路模板)
- [3.2 代码模板](#3.2 代码模板)
- 四、滑动窗口的使用时机
- 五、滑动窗口典型算法题目
-
- [5.1 长度最小的子数组](#5.1 长度最小的子数组)
- [5.2 无重复字符的最长子串](#5.2 无重复字符的最长子串)
- [5.3 最大连续 1 的个数 III](#5.3 最大连续 1 的个数 III)
- [5.4 将 x 减到 0 的最小操作数](#5.4 将 x 减到 0 的最小操作数)
- [5.5 水果成篮](#5.5 水果成篮)
- [5.6 找到字符串中所有字母异位词](#5.6 找到字符串中所有字母异位词)
- [5.7 串联所有单词的子串](#5.7 串联所有单词的子串)
- [5.8 最小覆盖子串](#5.8 最小覆盖子串)
- [💻结尾--- 核心连接协议](#💻结尾— 核心连接协议)
前言
深度进阶:滑动窗口算法核心秘籍
滑动窗口是一种在线性数据结构(如数组或字符串)上执行特定操作的算法优化技巧。它通过维护一个"窗口",并根据特定条件不断移动窗口的边界,从而将原本需要嵌套循环( O ( n 2 ) O(n^2) O(n2) 或 O ( n 3 ) O(n^3) O(n3))的复杂度降低到线性时间( O ( n ) O(n) O(n))
一、什么是滑动窗口?
1.1 核心机制:左右边界的律动
滑动窗口通常使用两个指针(left 和 right)来定义:
-
右边界
right扩张:寻找可行解。不断扩大窗口,将新元素包含进来。 -
左边界
left收缩:优化可行解。当窗口满足(或不再满足)某种特定条件时,收缩左侧以寻找"最优解"或使窗口重新符合规范。
滑动窗口本质上是对双指针技巧的深度优化
通过维护一组逻辑上连续的子序列(即"窗口"),在 O ( N ) O(N) O(N) 的时间复杂度内解决数组或字符串中的子区间类问题
1.2 🖼️ 滑动窗口动态演示:寻找和为 7 的连续子数组
假设数组为 [2, 3, 1, 2, 4, 3],我们要寻找和 ≥ 7 \ge 7 ≥7 的最小子数组长度
1. 窗口扩展阶段
右指针 right 向右移动,吸收新元素
Plaintext
指针位置: [ 2, 3, 1, 2, 4, 3 ]
L R (Window Sum = 2)
L R (Window Sum = 5)
L R (Window Sum = 6)
L R (Window Sum = 8) -> 触发条件!
2. 窗口收缩阶段
当条件满足时,左指针 left 向右移动,尝试压缩窗口寻找最优解
Plaintext
指针位置: [ 2, 3, 1, 2, 4, 3 ]
L R (Window Sum = 6) -> 不满足,停止收缩
否
是
Start
Right 指针右移
是否满足窗口条件?
记录/更新当前最优解
Left 指针右移
二、滑动窗口的两大分类
根据窗口长度是否固定,我们可以将其分为两类:
2.1 固定窗口
-
适用场景:求长度为 ( K ) 的子数组的最大和、计算固定长度的平均值等
-
操作逻辑:
-
先初始化第一个窗口
-
窗口整体向右平移:
cright++, left++; -
更新状态:
cnew_sum = old_sum + nums[right] - nums[left-1];
-
2.2 可变窗口
窗口的宽度随条件动态变化,这是算法面试中的高频考点
-
适用场景: 求满足条件的"最小子数组"或"最大不重复子串"
-
操作逻辑:
right主动向右移动- 在内部使用
while循环判断条件,动态收缩left
三、滑动窗口的通用模板
3.1 解题思路模板
无论是固定窗口还是变长窗口,其逻辑均可抽象为以下四部曲:
-
进窗 :右指针
right主动右移,将元素纳入窗口,更新窗口状态 -
判断:判断当前窗口是否触发特定条件(如窗口长度达到阈值、窗口内元素重复等)
-
出窗 :左指针
left被动右移,将元素移出窗口,同时恢复窗口状态 -
更新:在上述过程中,实时更新最终的结果(如最大长度、最小和等)
3.2 代码模板
cpp
void slidingWindow(string s, string t) {
unordered_map<char, int> window;
int left = 0, right = 0;
int valid = 0; // 记录窗口中满足条件的字符个数
while (right < s.size()) {
// a. c 是将移入窗口的字符
char c = s[right];
// 右移窗口
right++;
// 进行窗口内数据的一系列更新
...
/*** debug 输出的位置 ***/
// printf("window: [%d, %d)\n", left, right);
/********************/
// b. 判断左侧窗口是否要收缩
while (window needs shrink) {
// d 是将移出窗口的字符
char d = s[left];
// 左移窗口
left++;
// 进行窗口内数据的一系列更新
...
}
}
}
四、滑动窗口的使用时机
当你在处理连续的序列(数组或字符串)问题,且窗口的边界需要根据特定条件动态移动时,就是滑动窗口大显身手的时候
-
单调性 :滑动窗口本质上就是利用了单调性,规避很多没有必要的枚举
当窗口向右扩大时,窗口内的某个属性(如和、计数)具有单调递增或递减的特性,这允许我们通过移动左边界来恢复复合规律
-
线性数据结构:处理的对象是数组、字符串或链表。
-
连续性:题目要求找的是"子数组"、"子串"或"连续区间"。(如果是子序列或不连续组合,通常考虑动态规划或回溯。)
-
规模要求:寻找满足某种条件的最长/最短区间,或者特定长度的区间
五、滑动窗口典型算法题目
5.1 长度最小的子数组
5.2 无重复字符的最长子串
5.3 最大连续 1 的个数 III
5.4 将 x 减到 0 的最小操作数
5.5 水果成篮
5.6 找到字符串中所有字母异位词
5.7 串联所有单词的子串
5.8 最小覆盖子串
💻结尾--- 核心连接协议
警告: 🌠🌠正在接入底层技术矩阵。如果你已成功破解学习中的逻辑断层,请执行以下指令序列以同步数据:🌠🌠
【📡】 建立深度链接: 关注本终端。在赛博丛林中深耕底层架构,从原始代码到进阶协议,同步见证每一次系统升级。
【⚡】 能量过载分发: 执行点赞操作。通过高带宽分发,让优质模组在信息流中高亮显示,赋予知识跨维度的传播力。
【💾】 离线缓存核心: 将本页加入收藏。把这些高频实战逻辑存入你的离线存储器,在遭遇系统崩溃或需要离线检索时,实现瞬时读取。
【💬】 协议加密解密: 在评论区留下你的散列码。分享你曾遭遇的代码冲突或系统漏洞(那些年踩过的坑),通过交互式编译共同绕过技术陷阱。
【🛰️】 信号频率投票: 通过投票发射你的选择。你的每一次点击都在重新定义矩阵的进化方向,决定下一个被全量拆解的技术节点。

