前言
我是会写Bug的子晗,生命不止,算法永不息!
昨天晚上,闲来无事去学校acm队训练机房呆了一会,太受刺激了,大一的把我摁在地上摩擦,属实很拉,学习了一个滑动窗口算法。唉,现在算法刚开课,之前自己也学过一段时间,但刷体很少。以后晚上得经常去跟着他们一起去训练了,这种行为我愿称之为“偷学"。(手动滑稽)
算法思想
我个人觉得滑动窗口算法思想与双指针相似,模拟一个窗口,创建的窗口逐渐滑动,根据题目给定的限制条件,来更新窗口边界,从而不断的更新题目所需值,当窗口滑动至边界时,这时也意味着,算法结束,即可获得所需值。一般情况下,右边界主动滑动,左边界被动滑动。
俗话说的好,实践是检验真理的唯一标准!下面通过三道滑动窗口算法题来深层次理解滑动窗口算法的实际应用。
滑动窗口I
解题思路
通过设置两个指针,来作为窗口的边界,模拟窗口滑动,当窗口有右边界的字符已经存在于窗口内,左边界就需要更新。同时更新最大子串长度,当右指针移动至字符串末尾,窗口滑动完毕,所得值即为最大子串长度值。
代码
#include<bits/stdc++.h>
using namespace std;
int main()
{
string s;
while(getline(cin,s))
{
int i=0,j=0,curlen=0,maxlen=0;
if(s.length()==0)
{
cout<<0<<endl;
return 0;
}
for(;j<s.length();j++)
{
curlen++;
for(int k=i;k<=j;k++)//扫描有无重复字符
{
if(s[k]==s[j+1])//存在重复字符
{
if(curlen>maxlen) maxlen=curlen;//更新值
i=k+1;//跳过重复字符
curlen=j-i+1;//更新值
break;
}
}
}
maxlen=curlen>maxlen?curlen:maxlen;//更新值
cout<<maxlen<<endl;
}
return 0;
}
滑动窗口II
解题思路
设置两个双指针,右指针滑动,当值出现大于等于m的情况时,进行值的更新,然后将左指针滑动至小于m,右指针继续滑动至上述情况进行处理,直到右指针滑动至窗口边界,算法结束。
代码
#include<bits/stdc++.h>
using namespace std;
int main()
{
int Start=0,End=0,sum=0;
int res=10000000;
int n,m;
cin>>n;
int a[n];
for(int i=0; i<n; i++)
cin>>a[i];
cin>>m;
while(End<n)//右指针未到达边界
{
sum+=a[End];//右指针滑动
if(sum>=m)//出现大于等于m的情况
{
res=min(res,End-Start+1);更新值
while(sum>=m&&Start<=End)
{
res=min(res,End-Start+1);更新值
sum-=a[Start];
Start++;//左指针移动
}
}
End++;//不满足情况,右指针继续移动
}
if(res==10000000)
cout<<0<<endl;
else
cout<<res<<endl;
return 0;
}
111111
解题思路
设置双指针,右指针滑动,当遇到1时,继续滑动,当遇到0时,判断此时窗口内的0的个数是否等于题目给定的m,如果等于,左指针移动,直到去除一个0为止,为新的0腾出位置。如果小于m,右指针继续移动。然后进行值的更新,直到右指针移动至窗口边界,算法结束。
代码
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n,m,Max=0;
cin>>n;
int a[n];
for(int i=0;i<n;i++)
cin>>a[i];
cin>>m;
int left=0,right=0;
for(;right<n;right++)
{
if(a[right]==0)
{
if(m==0)//到达限制条件
{
while(a[left]==1)
left++;
left++;//去除一个0
}
else
m--;
}
Max=max(right-left+1,Max);//更新值
}
cout<<Max<<endl;
return 0;
}