1、算计简介
- 滑动窗口,即有一个大小可变的窗口,左右两端方向一致地向前滑动
2、适用范围
- 一般是字符串和列表
- 一般求最值或子序列
3、算法思想
- 适用双指针,初始化left=right=0,将索引闭区间[left,riht]称为一个窗口
- 先不断地增加right指针扩大窗口[left,right],直到窗口中的序列符合要求
- 此时,停止增加right,转而不断增加left指针缩小窗口[left,right],直到窗口中的序列不再符合要求。同时,每次增加left前,都要更新一轮结果
- 重复2和3,直到right到达序列的尽头
ps:第2步找到可行解,第3步优化这个解
4、算法模板
int left=0,right=0;
while(right未越界)
{
更新需要维护的变量;
---
情况1:窗口大小固定
//如果题目的窗口固定:需要判断当前窗口长度是否达到了限制长度窗口
//左指针移动一个单位,从而保证下一次右移时窗口长度不变;
//左指针移动前先更新需要维护的变量
if(窗口长度达到了限定长度)
{
更新维护变量;
窗口左指针右移一个单位,保证下一次右移时窗口长度不变;
}
---
情况2:窗口大小不固定
//此时需要考虑窗口是否合法
//如果当前窗口不合法,用一个while去不断低移动左指针,从而剔除非法元素直到窗口再次合法
//在左指针移动之前更新维护变量
while(不合法)
{
更新维护变量;
不断移动窗口左指针直到窗口再次合法;
}
return ...
}
5、例题
子数组最大平均数
题目描述:
给你一个由 n
个元素组成的整数数组 nums
和一个整数 k
。
请你找出平均数最大且 **长度为 **k
的连续子数组,并输出该最大平均数。
任何误差小于 10-5
的答案都将被视为正确答案。
解答
class Solution{
public:
double findMaxAverage(vector<int>& nums,int k)
{
//滑动窗口长度不变
//step 1
//本题求最大平均值(其实就是求最大和),需要定义sum_,max_avg
int sum=0,n=nums.size();
double max_avg=0.0;
//step 2
//定义滑动窗口的首尾端,然后滑动
int right=0,maxSum;
for(;right<k;right++)
sum+=nums[right];
maxSum=sum;
for(right=k;right<n;right++)
{
sum=sum-nums[right-k]+nums[right];
maxSum=max(maxSum,sum);
}
return (double)maxSum/k;//强制转换,保证浮点型输出
}
}
无重复字符的最长子串
题目描述:
给定一个字符串s,请你找出其中不含有重复字符的最长子串的长度
解答
class Solution
{
public:
int lenghthOfLongestSubstring(string s)
{
//step 1:定义需要维护的变量,本题求最大长度,需要定义max_len
//本题涉及去重,需要定义无需集合set
if(s.size()==0)
return 0;
int max_len=0;
unordered_set<char> lookup;//定义无序集合
int left=0;
for(int i=0;i<s.size();i++)
{
//step 2:检查窗口是否合法
//如果新加入的元素已经存在,则不合法,删除最左边的元素
while(lookup.find(s[i])!=lookup.end()){
lookup.erase(s[left]);//删除最左边的元素
left++;
}
max_len=max(max_len,i-left+1);
lookup.insert(s[i]);
}
return len_max;
}
}
至多包含两个不同字符的最长子串
题目描述:
给定一个字符串,找出至多包含两个不同字符的最长子串t
示例:
输入: "eceba"
输出: 3
解释: t 是 "ece",长度为3。
解答:
class Solution{
public:
int lengthOfLongestSubstringTwoDistinct(string s)
{
//step 1:定义需要维护的变量,本题求最多包含两个不同的最长子串,还需要定义不同的字母个数
int left=0,right=0;
int cnt=0;
int maxlen=0;
unordered_map<char> m;
//step 2:移动指针,并考虑窗口是否合法
for(;right<s.size();right++)
{
if(m[s[right]]==0)//出现新字符
cnt++;
m[s[right]]++;//计数加1
while(cnt>2)//窗口大于2
{
m[s[left]]--;
if(m[s[left++]]==0)
cnt--;
}
}
}
}