
🔥小龙报:个人主页
🎬作者简介:C++研发,嵌入式,机器人,AI等方向学习者
❄️个人专栏:《优选算法》
✨ 永远相信美好的事情即将发生

文章目录
- 前言
- 一、最大的连续1个数
-
- 1.1题目
- [1.2 算法原理](#1.2 算法原理)
-
- [1.2.1 算法思路](#1.2.1 算法思路)
- [1.2.2 算法流程](#1.2.2 算法流程)
- [1.3 代码](#1.3 代码)
- 二、找到字符串中所有字母的异位词
-
- [2.1 题目](#2.1 题目)
- [2.2 算法原理](#2.2 算法原理)
-
- [2.2.1 算法思路](#2.2.1 算法思路)
- [2.2.2 算法流程](#2.2.2 算法流程)
-
- [2.2.2.1 法一](#2.2.2.1 法一)
- [2.2.2.2 法二](#2.2.2.2 法二)
- [2.3 代码](#2.3 代码)
-
- [2.3.1 法一代码](#2.3.1 法一代码)
- [2.3.2 法二代码](#2.3.2 法二代码)
- 总结与每日励
前言
滑动窗口是算法面试高频考点,专门高效求解数组、字符串连续区间类题目,能将暴力解法 O (n²) 复杂度优化至线性 O (n)。本文选取两道经典例题:可变窗口题型水果成篮、定长窗口题型字母异位词,拆解滑动窗口结合哈希表的完整解题流程,区分两种窗口处理逻辑,附带可直接运行的 C++ 代码,帮读者吃透滑窗通用模板。
一、最大的连续1个数
1.1题目
链接:水果成蓝

1.2 算法原理
核心思想: 一段只包含两个数字的最长子串
1.2.1 算法思路
研究的对象是一段连续的区间,可以使用「滑动窗口」思想来解决问题。
让滑动窗口满足:窗口内水果的种类只有两种。
做法:
- 右端水果进入窗口的时候,用哈希表统计这个水果的频次。这个水果进来后,判断哈希表的大小:
- 如果大小超过 2:说明窗口内水果种类超过了两种。那么就从左侧开始依次将水果划出窗口,直到哈希表的大小小于等于 2,然后更新结果;
- 如果没有超过 2,说明当前窗口内水果的种类不超过两种,直接更新结果 ret。
1.2.2 算法流程
a. 初始化哈希表 hash 来统计窗口内水果的种类和数量;
b. 初始化变量:左右指针 left = 0,right = 0,记录结果的变量 ret = 0;
c. 当 right 小于数组大小的时候,一直执行下列循环:
i. 将当前水果放入哈希表中;
ii. 判断当前水果进来后,哈希表的大小:
● 如果超过 2:
○ 将左侧元素滑出窗口,并且在哈希表中将该元素的频次减一;
○ 如果这个元素的频次减一之后变成了 0,就把该元素从哈希表中删除;
○ 重复上述两个过程,直到哈希表中的大小不超过 2;
iii. 更新结果 ret;
iv. right++,让下一个元素进入窗口;
d. 循环结束后,ret 存的就是最终结果。
1.3 代码
cpp
class Solution {
public:
int totalFruit(vector<int>& fruits)
{
int map[100000] = {0};
int kind = 0; //统计当前区间内水果的种类
int l = 0,r = 0;
int n = fruits.size();
int ret = 0;
while(r < n)
{
//进窗口
if(map[fruits[r]]++ == 0)
kind++;
while(kind > 2) //窗口不合法 -- 水果种类大于2
{
if(map[fruits[l++]]-- == 1)
kind--;
}
ret = max(ret,r - l + 1);
r++;
}
return ret;
}
};
时间复杂度 : O(n)
二、找到字符串中所有字母的异位词
2.1 题目

2.2 算法原理
核心思想 :滑动窗口 + 哈希表
2.2.1 算法思路
cpp
异位词本质就是在一段区间内各个元素出现的次数和p字符串里各元素出现的次数相同
2.2.2 算法流程
2.2.2.1 法一
定义连个变量l,r来标识合法区间,定义两个哈希表,一个用来统计p串内各个元素出现的次数,另一个用来统计【l,r】区间内各个元素出现的次数并且和另一个哈希表做比较,看两个哈希表是否完全相同
2.2.2.2 法二
在法一的基础上定义个count来统计s中【l,r】有效字符个数的数量.最后和p元素长度作比较即可
有效字符个数,是在当前s串中的【l,r】区间中当该元素数量小于等于p串中该元素的数量则count加一,如果【l,r】是p的异位词则p的长度m必定和count相等。
2.3 代码
2.3.1 法一代码
cpp
class Solution {
public:
vector<int> findAnagrams(string s, string p)
{
vector<int> ret;
int hash1[26] = {0}; //统计p各元素出现次数
int hash2[26] = {0}; //统计s各元素出现次数
for(int i = 0;i < p.size();i++)
hash1[p[i] - 'a']++;
int l = 0,r = 0,n = s.size(),m = p.size();
while(r < n)
{
//进窗口
char ch = s[r];
hash2[ch - 'a']++;
if(r - l + 1 > m) //出窗口
hash2[s[l++] - 'a']--;
int f = 1;
for(int i = 0;i < 26;i++)
{
if(hash1[i] != hash2[i])
{
f = 0;
break;
}
}
if(f)
ret.push_back(l);
r++;
}
return ret;
}
};
2.3.2 法二代码
cpp
class Solution {
public:
vector<int> findAnagrams(string s, string p)
{
vector<int> ret;
int hash1[26] = {0}; //统计p各元素出现次数
int hash2[26] = {0}; //统计s各元素出现次数
for(int i = 0;i < p.size();i++)
hash1[p[i] - 'a']++;
int l = 0,r = 0,n = s.size(),m = p.size();
int count = 0; //统计当前【l,r】区间内有效字符的个数
while(r < n)
{
//进窗口
char ch1 = s[r];
if(++hash2[ch1 - 'a'] <= hash1[ch1 - 'a'])
count++;
if(r - l + 1 > m) //出窗口
{
char ch2 = s[l++];
if(hash2[ch2 - 'a']-- <= hash1[ch2 - 'a'])
count--;
}
if(count == m)
ret.push_back(l);
r++;
}
return ret;
}
};
时间复杂度 : O(N)
总结与每日励
✨ 本文通过两道典型题目梳理滑动窗口核心逻辑,可变窗口动态收缩左边界,限制窗口内元素种类;定长窗口维持固定区间,搭配哈希统计字符频次。优化解法引入计数变量,省去逐一枚举 26 个字母比对,进一步简化逻辑。两类题目均仅一次遍历数组,时间复杂度稳定 O (n)。掌握窗口伸缩规则与哈希表状态维护,就能快速应对绝大多数滑动窗口题型。代码一行行敲,算法一道道啃,所有看似晦涩的逻辑,都会在反复练习中变得通透。不必畏惧刷题路上的卡顿与报错,每一次调试都是沉淀。沉下心深耕基础,稳步积累,那些默默付出的时光,终会化作面试与竞赛里稳稳的底气,永远相信美好的事情即将发生。
