滑动窗口+leetCode题3

曩 ,遇到滑动窗口的题时往往条件发射似的就用滑动窗口的方法解决,也没有细想什么情况下用;

今,慕然回首,发现是时候展现其真正的技术了,总结使知识更清晰牢固嘛;

故,认真分析一波滑动窗口这个东西的核心内容、具体操作、应用对象,并结合了一道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的内容,请移步至其他更好的资料,但如果本篇文章对您有帮助,我深感荣幸!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
滑动窗口是一种常用的算法技巧,可以用于解决一类问,其中包括一些LeetCode上的目。通过维护一个窗口,我们可以在线性时间内解决一些需要处理连续子数组或子字符串的问。以下是一些常见的滑动窗口: 1. 最小覆盖子串(Minimum Window Substring):给定一个字符串S和一个字符串T,在S中找出包含T所有字符的最小子串。 2. 字符串的排列(Permutation in String):给定两个字符串s1和s2,判断s2是否包含s1的排列。 3. 找到字符串中所有字母异位词(Find All Anagrams in a String):给定一个字符串s和一个非空字符串p,找到s中所有是p的字母异位词的子串。 4. 替换后的最长重复字符(Longest Repeating Character Replacement):给定一个只包含大写英文字母的字符串s,你可以将一个字母替换成任意其他字母,使得包含重复字母的最长子串的长度最大化。 5. 至多包含两个不同字符的最长子串(Longest Substring with At Most Two Distinct Characters):给定一个字符串s,找出至多包含两个不同字符的最长子串的长度。 以上只是几个例子,滑动窗口可以应用于更多类型的问。在解决这些问时,我们通常使用两个指针来表示窗口的左右边界,并根据具体问的要求移动窗口。在每次移动窗口时,我们可以更新窗口的状态,例如统计字符出现次数、判断窗口是否满足条件等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值