它是一个运行在一个大数组上的子列表,该数组是一个底层元素集合。假设有数组 [a b c d e f g h ],一个大小为 3 的 滑动窗口 在其上滑动,则有:
[a b c]
[b c d]
[c d e]
[d e f]
[e f g]
[f g h]
一般情况下就是使用这个窗口在数组的 合法区间 内进行滑动,能够极大地提高算法地效率
滑动窗口的思想
在具体使用之前,我们知道窗口实际是两个指针之间形成的区域,那关键就是这两个指针是如何移动的。
- 初始时,左右指针left,right都指向第0个元素,窗口为[left,right),注意这里是左闭右开,因此初始窗口[0,0)区间没有元素,符合我们的初始定义
- 开始循环遍历整个数组元素,判断当前right指针是否超过整个数组的长度,是退出循环,否则执行第3步
- 然后right指针开始向右移动一个长度,并更新窗口内的区间数据
- 当窗口区间的数据满足我们的要求时,右指针right就保持不变,左指针left开始移动,直到移动到一个不再满足要求的区间时,left不再移动位置
- 执行第2步
这中间,窗口的更新与维护是很重要的一环,新元素加入窗口,旧元素移出窗口,都需要及时地更新与这个窗口范围相关的数据。
上述说明主要是两个while循环,可以简单抽象成一个模板如下:
int left = 0,right =0;
while(right指针未越界){
char ch = arr[right++];
//右指针移动,更新窗口
...
//窗口数据满足条件 对于固定窗口而言,就是窗口的大小>=固定值;对于动态窗口,就是从left出发,窗口不断扩充,第一次满足题意的位置
while(窗口数据满足条件){
//记录或者更新全局数据
...
//右指针不动,左指针开始移动一位
char tmp = arr[left++];
//左指针移动,窗口缩小,更新窗口数据
...
}
//返回结果
...
}```
## 滑动窗口的几个例题应用
**例1**

滑动窗口算法可以解决字符串的子串中的几类应用问题
主要思想是:left与right同时从0开始变化,哈希表所记录的dict如果出现不止一次,那么就把左边界重新赋值到新出现的位置,右边界不管咋样都向后一个一个的移动,每次都记录下max,max为右减左再加一,因为从0开始。
图解:

源代码:
```cpp
#include<stdio.h>
#include<String.h>
int lengthOfLongestSubstring(char * s){
if (s == NULL) return 0;
int max = 0; //记录最长的长度max
int left = 0, right = 0; //滑动窗口的左边界和右边界
int dict[256] = {0}; //和前面的排序一样,搞个类似于哈希表的东西,通过数组记录其出现的相应次数;
int index;
for (; s[right] != '\0' ; right++){
index = s[right]; //得到对应字符的下标
if(dict[index] > left)
left = dict[index];
dict[index] = right+1; //注意:到只有一个字符时长度为1,所以这里右边界要加1
if (max < right-left+1)
max = right-left+1; //更新最大值
}
return max;
}
main(){
char a[99];
gets(a);
int n;
n = lengthOfLongestSubstring(a);
printf("%d",n);
}
例2
同样使用滑动窗口的办法解决,每次循环都求和,同时右边界移动,当和大于目标值时,进入最小值的判断,如果是第一次进入,则让最小值为此时右边界减0,同时sum把左边界的值减去,左边界移动一个,如果不是第一次进入最小值的判断,那么最小值就是右减左边界(此时左边界已经移动)如果不大于目标值则继续原始循环,直到数组的头。
int minSubArrayLen(int s, int* nums, int numsSize){
int left = 0;
int right = 0;
int min = 0;
int sum = 0;
while (right < numsSize){
sum += nums[right];
right++;
while (sum >= s){
if (min == 0){
min = right - left;
}
else{
if(min > right - left)
min = right - left;
}
sum -= nums[left];
left++;
}
}
return min;
}