曩 ,遇到滑动窗口的题时往往条件发射似的就用滑动窗口的方法解决,也没有细想什么情况下用;
今,慕然回首,发现是时候展现其真正的技术了,总结使知识更清晰牢固嘛;
故,认真分析一波滑动窗口这个东西的核心内容、具体操作、应用对象,并结合了一道leetCode上的题3,在深入领悟一下我的领悟。
一,滑动窗口
根据我的认知知识的顺序,看到滑动窗口首先想到计算机网络中的滑动窗口,于是它的样子呈现在我脑海在中:
计算机网络中的滑动窗口:
1,窗口:窗口内是一段连续的子序列;
2,滑动:窗口向一个方面前进,这个前进是通过右边界的拓展和左边界的收缩实现的(而不是把窗口向前推了);
3,大小:窗口的大小会变化。
然后算法中的滑动窗口也基本是这个意思,于是这样就对算法的滑动窗口有了基本的认识,下面直接总结我所认为的滑动窗口的精髓或应该注意的地方:
1,核心(滑动窗口的灵魂)
当窗口不满足要求时,右边界向右拓展边界;
当窗口满足要求时,左边界向右收缩边界。
当然,具体问题还要具体分析!
2,具体操作
滑动窗口往往结合双指针,用两个指针表示整个序列的子序列(滑动窗口)的左右边界;
拓展边界则是向右移动右子针,收缩边界则是向左移动左子针。
3,搭档
一些题目中的滑动窗口多搭档Hash表使用(这与滑动窗口的使用场景右关),使用Hash表用于判断重复的次数;
滑动窗口左指针右移时,从Hash表中移除一个序列的基本单位;
滑动窗口右指针右移时,往Hash表中添加一个序列的基本单位;
此时,可用HashSet记录窗口内是否有重复的元素,用HashMap记录窗口内每个元素出现的次数(当然这是针对java语言来说)。
二,leetCode题3
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
示例1:
输入: s = “abcabcbb”
输出: 3
解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。
为了更加深入理解滑动窗口,先在这里捋一捋暴力解法的思路,以此形成对比。
暴力破解:
遍历整个字符获得所有子串并判断字串是否符合要求(不含有重复字符),最后得出最长的字串的长度;
程序的结构大概就是,
第一次遍历,遍历整个字符串的字符,确定子串开头的字符;
在第一次遍历的循环内,进行第二次遍历,从遍历字串开头的字符的确定字串结尾的字符;
在第二次遍历的循环内,判断字串是否符合不含有重复字符从要求。
到这里,已经两层嵌套循环了!
而,滑动窗口:
初始状态窗口内为空,不符合要求(长度没有达到最大),尝试向右拓展边界的:a
不符合,继续向右得:ab
不符合,继续向右得:abc
不符合,继续向右得:abca,这时,发现a已经存在,满足要求(前一个子串长度最大),左指针开始向右收缩边界得:bca
不符合,继续向右得:bcab,这时,发现b已经存在,满足要求(前一个子串长度最大),左指针开始向右收缩边界得:cab
…
可以看出,整个过程只需要一次遍历整个序列!
滑动窗口的另一优良特性:
在一个场景中,计算某个整数序列中的5个数的和的最大的值,比如:3 -15 9 20 -7 5 6
通过滑动窗口:
初始窗口,内数字为3 -15 9 20 -7:3+(-15)+9+20+(-7)= 10
窗口右滑,此时窗口内-15 9 20 -7 5 :10-3+5=12,而不是采用(-15)+9+20+(-7)+5的方式计算,因为窗口内有大部分重复的内容,这样便少做了2次运算。
来自leetCode的题3官方讲解视频中(相当于题眼吧):
模式识别1,涉及子串,考虑使用滑动窗口(当然,我往往感觉它要用滑动窗口)
模式识别2,一旦涉及次数,需要用散列表,通常字符为键,次数为在值
这里附上我的代码:
class Solution {
public int lengthOfLongestSubstring(String s) {
int pL = 0;//滑动窗口的左边界
int pR = -1;//滑动窗口的右边
int ans = 0;//保存最大的字串长度
Set timesSet = new HashSet();
while(pR+1 < s.length())
{
//向右扩展边界
pR+=1;
//如果新扩展来的字母已存在HahsSet中
if(timesSet.contains(s.charAt(pR)))
{
//向右收缩边界(找到这个字母并删除前面的所有字母)
while(s.charAt(pL)!=s.charAt(pR))
{
timesSet.remove(s.charAt(pL));
pL+=1;
}
pL+=1;
}
else
{
//将新扩展的字母加入HashMap
timesSet.add(s.charAt(pR));
}
ans = Math.max(ans,pR-pL+1);
}
return ans;
}
}
运行时间7ms,消耗内存38.4M。
这篇文章大概为自己总结了,滑动窗口的使用方法和优点,重点是具体的核心思想和具体的操作。我想掌握了核心思想和具体操作之后,便可以比较轻松的应用了。
本篇文章目的是要将所遇到的问题总结一下使自己对知识更加清晰和扎实并方便自己日后回顾,所以本篇文章在编写的过程中没有规划,想到哪写道哪,导致逻辑不够清晰、表达不够清楚和简练,勿喷,但接收虚心的交流和指导;如果您是想学习滑动窗口的内容或leetCode题3的内容,请移步至其他更好的资料,但如果本篇文章对您有帮助,我深感荣幸!