leetcode - 滑动窗口问题集

leetcode题库 原题链接 2、dict集合(哈希表)解法 Java解法 1、暴力解法 2、HashMap集合(哈希表)解法 阅读详情

目录

前言

题1 长度最小的子数组:

思考:

参考代码1:

参考代码2:

题2 无重复字符的最长子串:

思考:

参考代码1:

参考代码2:

题3 最大连续1的个数 III:

思考:

参考代码:

题4 将 x 减到 0 的最小操作数:

思考:

参考代码:

题5 水果成篮:

思考;

参考代码1:

参考代码2:

参考代码3:

题6 找到字符串中所有字母异位词:

思考:

参考代码1:

参考代码2:

题 7 串联所有单词的子串:

思考:

参考代码:

题8 最小覆盖子串 :

思考:

参考代码1:

参考代码2:

总结


前言

路漫漫其修远兮,吾将上下而求索;


以下是滑窗口问题leetcode 集,大家可以先自己做做看:

  1. 209. 长度最小的子数组
  2. 3. 无重复字符的最长子串
  3. 1004. 最大连续1的个数 III
  4. 1658. 将 x 减到 0 的最小操作数
  5. 904. 水果成篮
  6. 438. 找到字符串中所有字母异位词
  7. 30. 串联所有单词的子串
  8. 76. 最小覆盖子串

题1 长度最小的子数组:

209. 长度最小的子数组 - 力扣(LeetCode)

题干:

数据范围:

例子:

思考:

子数组:连续的数据

解法一:暴力枚举出所有子数组的情况,然后将其中的数据相加判断和是否大于target ;

这样的话,时间复杂度为O(N^3),并且本题的数据量不少,单纯地用暴力解决一定会超时;可以在暴力解法的基础上进行优化吗?无非就是在优化枚举所有子数组,计算该子数组的和这两点上进行优化;

由于数组中的数据均是正整数,正整数做加法有这样的性质:加的数越多,和就越大(利用了数据的单调性);

和前一篇“双指针题集”有相同之处,此处也可以利用数据的单调性来优化枚举所有子数组,而且还顺便可以优化计算其和:

  • 假设我们两个指针(假设为left right, 这两个指针是同向走的)指向的区间中的数据为sum ,当sum 刚好大于target 的时候,可以再用一个变量记录此时子数组的长度;此时sum 已经大于target 了,那么可以让left++ ,减去前面较小的数看sum 是否还大于target ,如果还大于left 可以继续++,如果小于了就让right ++;(整体思路很像双指针)

稍微粗略的分析觉得可行之后,我们可以更加细节地分析:

优化计算子数字的和:固定左区间,再定义一个变量来一直计算,这样就不用每遇到一个区间就从头到尾依次计算,图解如下:(下图的target 为 7)

当sum 已经大于target 的时候,此时left 和 right 的区间就已经为较小子数组长度下的和,right 也没有必要继续向前走了;

优化:当sum 已经大于target 的时候,让变量记录一下该子数组的长度,然后让left ++ ,再让right 回到left 指向的位置上,如下:

倘若当我们找到一个符合要求的区间之后让left 自增,然后再让right 指向left 指向的字符,那么就会需要将sum 置为0,然后一个一个地再遍历,计算该子数组中数据中的和;时间复杂度为O(N^2);实际上,还可以继续优化:当left 和 right 指向的区间中的数据和大于target 的时候,left ++ ,但是right 并不回到left 指向的位置处,而是让right 不动,sum 减去left 之前所指向的数据,再判断sum 和 target 的大小关系,如果sum 还是大于target ,left 继续++ ,sum 再减去left 之前所指向的数,然后再判断sum 和 target 的大小关系……如果sum小于target ,right 就++……优化二如下图:

对于优化2的操作,本质上就是滑动窗口的理念,即利用单调性,并且使用同向双指针;利用滑动窗口一般是来维护一个区间;

思路总结:

按照上面的思路写代码,我们会发现:

在出窗口的位置要写成循环:

参考代码1:

(while 循环版本)

    int minSubArrayLen(int target, vector<int>& nums) 
    {
        int n = nums.size();
        //单调性 + 同向双指针
        int left = 0, right = 0;
        int sum = 0, retlen = INT_MAX;
        while(right < n)
        {
            //当sum 小于target 就入窗口
            sum+=nums[right];
            while(sum >= target)
            {
                //此时sum >= target ,满足题干条件,可以更新结果,并且出窗口
                retlen = min(retlen , right-left+1);
                sum-=nums[left++];
            }
            right++;
        }
        return retlen==INT_MAX?0:retlen;
    }

Q:为什么right++ 放在出窗口后面?不应该是先入窗口然后再出窗口吗?

  • 最初left == right 的时候(left ==0 , right == 0),实际上是将第一个数入窗口,相当于right天然地就已经自增了;所以将right++,放在最后,每次right向后走一步就入窗口,是合理的;

基于此,我们还可以写成for 循环版本的:

参考代码2:

(for 循环版本)

    int minSubArrayLen(int target, vector<int>& nums) 
    {
        int n = nums.size();
        //单调性 + 同向双指针
        int sum = 0, retlen = INT_MAX;
        for(int left = 0, right = 0;right <n;right++)
        {
            //当sum 小于target 就入窗口
            sum+=nums[right];
            //更新数据 + 出窗口 
            while(sum >= target)
            {
                //此时sum >= target ,满足题干条件,可以更新结果,并且出窗口
                retlen = min(retlen , right-left+1);
                sum-=nums[left++];
            }
        }
        return retlen==INT_MAX?0:retlen;
    }

题2 无重复字符的最长子串:

3. 无重复字符的最长子串 - 力扣(LeetCode)

题干:

数据范围:

例子:

思考:

子串:连续的字符构成的串

要求:不重复的最长子串

解法一:暴力解法

列举出所有的子串的情况,再判断这每一个子串是否是不重复的子串,然后找到一个最长的就可以了;其中枚举所有子串的情况:固定每一个有可能的起始位置,然后依次向后扩展,直到扩展到不能再扩展为止;而判断这个子串是否重复:利用哈希表;

即暴力解法就是:暴力枚举 + 哈希表判断;

此处就不演示暴力解法是否能通过,我们需要做的是能否在暴力解法的基础上进行优化:这道题其实和上一道题有异曲同工之妙,只不过上一道题出窗口的条件是:当sum >= target, 而本题出窗口的条件:窗口[left,right] 之中有重复的字符,图解如下:

我们需要想清楚的是,当hash 之中出现了重复的字符的时候我们要怎么做?

方法一:根据暴力枚举的想法,left ++,然后right 指向left 指向的位置;

显然这种方式处理出现重复的字符的情况,不仅会有无效情况的加入,还要清空hash表重新记录,时间复杂度仍是O(N^2)

方法二:既然从方法一我们已经得知,当遇到重复的字符时,left++,right 回到left 指向的位置,还是没有解决重复字符的问题,只有越过这个重复的字符才能从根源上解决问题;

如何越过呢?

  • left一直向前走,每走一步都要判断hash 之中是否还存在重复的字符,直到hash 之中没有重复的字符了,left 才停止向前走,此时出窗口结束,并且需要更新结果,图解如下:

参考代码1:

    int lengthOfLongestSubstring(string s) 
    {
        int n = s.size(),retlen = INT_MIN;
        //同向双指针 + hash判断窗口中是否有重复的数据
        unordered_map<char,int> hash;
        for(int left = 0 , right = 0;right < n;right++)
        {
            //入窗口
            if(hash[s[right]] == 0) hash[s[right]] = 1;
            else
            {
                hash[s[right]]++;
                //出窗口
                while(hash[s[right]]==2)
                {
                    hash[s[left++]]--;
                }
            } 
            //更新结果 - 走到这里就意味着没有重复字符
            retlen = max(retlen , right-left+1);
        }
        return retlen==INT_MIN?0:retlen;
    }

由于题干说了字符串s 由英文字母、数字、符号和空格组成,所以在实现hash 的时候可以不用容器unordered_map ,可以使用128大小的整形数组,用下标来映射字符;参考代码2换成while 循环来实现,并且可以优化其代码逻辑,right 指向的字符每要入一次都要检查,那么同一个字符出现的个数最大为2,可以直接入窗口,然后再判断出窗口,走到了此处,此时窗口[left,right] 中的字符一定不会重复,所以可以更新数据,如下:

参考代码2:

    int lengthOfLongestSubstring(string s) 
    {
        int n = s.size(),retlen = INT_MIN;
        //同向双指针 + hash判断窗口中是否有重复的数据
        //可以使用大小为128的字符数组来实现hash
        int hash[128] ={0};
        int left = 0 , right = 0;
        while(right < n)
        {
            //入窗口
            hash[s[right]]++;
            //判断  - 出窗口
            while(hash[s[right]]==2)
            {
                hash[s[left++]]--;
            }
            //更新结果 - 走到这里就意味着没有重复字符
            retlen = max(retlen , right-left+1);
            right++;
        }
        return retlen==INT_MIN?0:retlen;
    }

这两个参考代码的时间复杂度均为O(N);

题3 最大连续1的个数 III:

1004. 最大连续1的个数 III - 力扣(LeetCode)

题干:

数据范围:

例子:

思考:

题干意思就是一个数组中只有0和1,可以将k个0变成1,求连续1的最长连续长度;

那么首先想到的肯定是暴力解法,枚举出所有的子数组,然后将子数组中k个0全部变为1,再求最长的子数组的长度;即枚举 + 判断,经过前面两道题的练习不难想到,想要高效地枚举,可以利用同向双指针来解决;而至于判断窗口中将k 个0变为1能否构成全1,可以借助于窗口的总数与数据个数的关系,例如:假设窗口中的数据有5个,k为3,那么该窗口中的数据总和的范围为[2,5] ,即[n-k,n] 一旦不在这个范围就一定不能构成连续1的子数组;那这样的话,时间复杂度依旧是O(N^2),因为没有实质性地解决枚举的消耗高的问题,需要砍掉一些可能性来降低时间复杂度;那么就得从k 入手,当窗口中的0的个数大于k个的时候,出窗口,图解如下:

思路总结:

参考代码:

    int longestOnes(vector<int>& nums, int k) 
    {
        int n = nums.size(),count = 0, retlen = INT_MIN;
        //同向双指针 + 一个变量来记录窗口中0的个数
        for(int left =0 , right = 0; right < n;right++)
        {
            //入窗口
            if(nums[right]==0) count++;
            while(count>k)
            {
                if(nums[left]==0) count--;
                left++;
            }
            //此时窗口中0的个数一定合法,可以更新数据
            retlen = max(right-left+1, retlen);
        }
        return retlen;//因为数组中至少有一个数据,所以不用判断retlen 是否会为INT_MIN
    }

可以再简洁该代码,如下:

    int longestOnes(vector<int>& nums, int k) 
    {
        int n = nums.size(),retlen = INT_MIN;
        //同向双指针 + 一个变量来记录窗口中0的个数
        for(int left =0 , right = 0,count = 0; right < n;right++)
        {
            //入窗口
            if(nums[right]==0) count++;
            while(count>k)
                if(nums[left++]==0) count--;
            //此时窗口中0的个数一定合法,可以更新数据
            retlen = max(right-left+1, retlen);
        }
        return retlen;//因为数组中至少有一个数据,所以不用判断retlen 是否会为INT_MIN
    }

题4 将 x 减到 0 的最小操作数:

1658. 将 x 减到 0 的最小操作数 - 力扣(LeetCode)

题干:

数据范围:

例子:

思考:

从nums 的最左边或者最右边选择一个数据,让x 减去,求让x 减为0的最少选数次数;

我们先来思考一下如何才可以让x减去一些数之后值为0?

  • 显然这些数相加要为x。

那么最少的操作次数呢?

  • 用最少的数相加为x;

那么每次只能选最左边或者最右边的数据该如何解决呢?

  • 首先我们想到的是在左右两边均设置一个指针,一个一个地试。

但是选这个数的时候我们怎么知道这个数合不合适呢?

显然这是非常矛盾的;画图再分析一下:

所得到的结果无非就是这三种情况中的一个,其共同点都是需要蓝色区域中的数据相加和为x ,并且求该区域中数据的最少个数,那么空白区域中数据的和为 sum-x ,则反过来就是求空白区域的最多数据个数;

而,空白区域无论在哪一个情况下均是连续的区域,我们是否可以将题干中的意思进行转换?换一个角度解决问题?

题干转换:找出nums中最长的和为(sum-x) 的子数组的长度;

解法一:暴力解法 + 计算和

枚举出所有子数组的情况,并计算其和是否等于 (sum-x) ,并且求出最长的和为 (sum-x)的 子数组的长度;

解法一一定是首先就能想到的解法,但是经过前面三道题的训练,应该可以敏感地感知,此处还可以用同向双指针进行优化,即解法二;

解法二:根据暴力解法进行优化

由题干中的信息可以知道,nums 中的数据均为正整数,所以数据就已经有了天然的单调性-> 数据的个数越多,其和越大;可以利用同向双指针来解决,假设同向双指针为left ,right ,范围[left,right] 中的数据总和为sum ,当sum > target 的时候,就要减少窗口中的数据个数来以此减小sum,即在left 窗口,出窗口可能会多次操作,故而应该用循环解决;当sum < target ,应该增加窗口中的数据个数来增大sum ,所以从right 处入窗口;当sum == target 的时候,就是我们的目标情况,此时需要更新数据;其中target 在本题中为nums 的总和减去x;

思路总结:

还有一个细节的地方,如果题干所要求的x 本身就大于nums 中的数据总和,那么是一定在nums 中找不到数据相加结果为x , 直接返回-1即可;

参考代码:

    int minOperations(vector<int>& nums, int x) 
    {
        //转换题意:t:nums总和-x ,寻找和为t 的最多数据个数的子数组
        int sumnums = 0, n = nums.size();
        for(auto e: nums) sumnums+=e;
        int target = sumnums - x;
        //如果x大于nums中左右数据的总和是一定找到不的;
        if(target < 0) return -1;
        int left = 0, right = 0, sum = 0 , retlen = INT_MIN;//同向双指针
        while(right < n)
        {
            //入窗口
            sum += nums[right];
            //判断sum 与 target 的大小关系,决定是否要出窗口
            while(sum > target)
            {
                sum-=nums[left++];
            }
            //如果sum == target 就更新数据
            if(sum == target) retlen = max(retlen , right-left+1);
            right++;
        }
        //retlen 可能还是为INT_MIN,就说明没有找到
        if(retlen == INT_MIN) return -1;
        else return n - retlen;
    }

题5 水果成篮:

904. 水果成篮 - 力扣(LeetCode)

题干:

数据范围:

例子:

思考;

题干的意思可以提炼为:从正整数数组nums的任意一个位置开始,向右连续地选数,只能选两种数,求最多地数据个数,窗口[left,right] 中只能有两种数字;

注:此处的nums 表示题干中的数组fruits,用nums 来解释比较好理解,下文的阐述中也是用nums 代表 fruits 来阐述的;

解法一:暴力解法:

枚举出所有的子数组,判断该子数组中是否只存在两种数字,并且求满足条件的最长的子数组长度;枚举就不用多说,固定一个位置挨个枚举即可;如何判断一个区间中的数据种类?利用哈希表来解决;根据数据范围可以得知,数组nums 中最大的数值为99999,可以是开辟大小为100001的数组当作哈希表,也可以利用容器unordered_map 来解决;

看到连续的子数组的题目,我们肯定可以联想到为可以利用同向双指针来解决,从暴力解法上进行优化;

解法二:同向双指针 - 滑动窗口

需要利用变量kinds统计窗口中的数据种类,当kinds 小于等于2 的时候继续入窗口,当kinds大于2的时候出窗口,kinds 合法的时候就要更新数据;其实很像本博文中的题2  无重复字符的最长子串,只不过两个判断出窗口时的条件不同;

此处就不赘述了,思想真的一模一样;

参考代码1:

    int totalFruit(vector<int>& fruits) 
    {
        int n= fruits.size();
        //hash
        unordered_map<int,int> hash;
        int left = 0, right = 0, retlen = INT_MIN, kinds = 0;
        while(right < n)
        {
            //入窗口
            hash[fruits[right]]++;
            if(hash[fruits[right]] == 1) kinds++;
            //判断是否要出窗口
            while(kinds>2)
            {
                hash[fruits[left]]--;
                if(hash[fruits[left]]==0) kinds--;
                left++;
            }
            //到了此处的kinds一定合法,更新数据
            retlen = max(retlen , right - left +1);
            right++;
        }
        //因为fruits 中至少有一个数,直接范围即可不用进行判断
        return retlen;
    }

实际上我们利用unordered_map容器来实现哈希表就可以不使用变量来记录窗口中的数据种类,直接使用接口函数 size() 、erase() 等来实现就可以了,如下:

参考代码2:

    int totalFruit(vector<int>& fruits) 
    {
        int n= fruits.size();
        //hash
        unordered_map<int,int> hash;
        int left = 0, right = 0, retlen = INT_MIN;
        while(right < n)
        {
            //入窗口
            hash[fruits[right]]++;
            //判断是否要出窗口
            while(hash.size()>2)
            {
                hash[fruits[left]]--;
                if(hash[fruits[left]]==0) hash.erase(fruits[left]);
                left++;
            }
            //到了此处的kinds一定合法,更新数据
            retlen = max(retlen , right - left +1);
            right++;
        }
        //因为fruits 中至少有一个数,直接范围即可不用进行判断
        return retlen;
    }

实际上在unordered_map 中频繁地插入、删除,效率十分低下,可以这么说,参考代码2的效率没有参考代码1 的高,此处还有一种写法,就是hash 用数组来实现,用空间换时间,直接开辟大小为100001的空间,最终代码与参考代码1如出一辙,只不过是hash 实现的不同罢了;

参考代码3:

    int totalFruit(vector<int>& fruits) 
    {
        int n= fruits.size();
        //hash
        int hash[100001] = {0};
        int left = 0, right = 0, retlen = INT_MIN, kinds = 0;
        while(right < n)
        {
            //入窗口
            hash[fruits[right]]++;
            if(hash[fruits[right]] == 1) kinds++;
            //判断是否要出窗口
            while(kinds>2)
            {
                hash[fruits[left]]--;
                if(hash[fruits[left]]==0) kinds--;
                left++;
            }
            //到了此处的kinds一定合法,更新数据
            retlen = max(retlen , right - left +1);
            right++;
        }
        //因为fruits 中至少有一个数,直接范围即可不用进行判断
        return retlen;
    }

题6 找到字符串中所有字母异位词:

438. 找到字符串中所有字母异位词 - 力扣(LeetCode)

题干:

数据范围:

例子:

思考:

即在字符串s 中找有字符串p 中字符构成的子串,返回首字母的下标;

Q:如何判断两个字符串是否为”异位词“?

eg: s1 = "aabac"  , s2="abaca"

方法一:先为这两个字符串排序,然后利用两个指针对其内容进行一一比对;时间复杂度为O(Nlogn+N),如下:

方法二:不考虑每个字符串中的字符的顺序怎么样,只是判断这两个字符串中的字符种类与个数是否相同即可,如下:

而至于如何判断,我们可以借助于哈希表来实现;

解法一:暴力解法

暴力枚举出字符串s 中所有子串的情况,然后利用hash表来判断列举出来的子串是否与字符串p构成”异位词“;

创建两个哈希表 hash1 与 hash2  , 先将字符串p 中的字符放入hash2 之中,然后再将列举出来的子串放入hash1 之中,最后再比较hash1 与 hash2是否相等即可;相等的,便可以将该子串的首字符下标放入返回的数组之中;

我们现在思考的是能否在暴力解法的基础上进行优化?首先是枚举出所有的子串,实际上有些子串根本就没有枚举的必要,例如已知这个子串中出现了非字符串p 中的字符;基于这点,如果哈希表是用容器unordered_map 实现的话,就可以使用接口函数 count() 来查找hash2 中是否有这个字符;而维护一段连续的区域,我们不难想到会使用同向双指针来解决;

解法二:同向双指针 + hash

Q:如何比较两个哈希表是否相同? 

因为题干说了字符串中的字符全为小写字符,所以还可以使用大小为26 的数组来实现hash;

解决方法一:直接比较,若哈希表用数组实现的话,比较26次就可以了;

如若哈希表用unordered_map 实现的话,就需要设置一个变量来统计窗口中有效数据的个数,并且在统计的时候还需要结合hash2与hash1 字符的个数来实现;那么同样的,再增加一个变量记录窗口中有效数据的个数就可以了;

思路总结:

参考代码1:

    vector<int> findAnagrams(string s, string p) 
    {
        int m = s.size(), n = p.size();
        unordered_map<char , int> hash1,hash2;
        //将字符串p 中的字符均放入hash表中
        for(auto e : p) hash2[e]++;
        int left = 0, right = 0, count = 0;
        vector<int> ret;
        while(right < m)
        {
            //入窗口
            char in = s[right];
            hash1[in]++;
            if(hash2.count(in) && hash1[in] <= hash2[in]) count++;
            //判断是否要出窗口
            //因为一定只会执行一次,所以可以写成if 判断语句
            if(right - left + 1 > n)
            {
                char out = s[left];
                //维护count
                if(hash2.count(out) && hash1[out] <= hash2[out]) count--;
                hash1[out]--;
                left++;
            }
            //更新结果 - 窗口中的数一定是小于等于n 的
            if(count == n) ret.push_back(left);
            right++;
        }
        return ret;
    }

如果用变量记录有效数据个数的,还可以用数组实现的hash代替unordered_map ,但是需要注意下标的映射关系,如下:

参考代码2:

    vector<int> findAnagrams(string s, string p) 
    {
        int m = s.size(), n = p.size();
        int hash1[26] = {0};
        int hash2[26] = {0};
        //将字符串p 中的字符均放入hash表中
        for(auto e : p) hash2[e - 'a']++;
        int left = 0, right = 0, count = 0;
        vector<int> ret;
        while(right < m)
        {
            //入窗口
            char in = s[right];
            hash1[in - 'a']++;
            if(hash1[in - 'a'] <= hash2[in - 'a']) count++;
            //判断是否要出窗口
            //因为一定只会执行一次,所以可以写成if 判断语句
            if(right - left + 1 > n)
            {
                char out = s[left];
                //维护count
                if( hash1[out - 'a'] <= hash2[out - 'a']) count--;
                hash1[out - 'a']--;
                left++;
            }
            //更新结果 - 窗口中的数一定是小于等于n 的
            if(count == n) ret.push_back(left);
            right++;
        }
        return ret;
    }

还可以对代码进行简化,如下:

    vector<int> findAnagrams(string s, string p) 
    {
        int m = s.size(), n = p.size();
        int hash1[26] = {0};
        int hash2[26] = {0};
        //将字符串p 中的字符均放入hash表中
        for(auto e : p) hash2[e - 'a']++;
        int left = 0, right = 0, count = 0;
        vector<int> ret;
        while(right < m)
        {
            //入窗口
            char in = s[right];
            if( ++ hash1[in - 'a'] <= hash2[in - 'a']) count++;
            //判断是否要出窗口
            //因为一定只会执行一次,所以可以写成if 判断语句
            if(right - left + 1 > n)
            {
                char out = s[left++];
                //维护count
                if( hash1[out - 'a']-- <= hash2[out - 'a']) count--;
            }
            //更新结果 - 窗口中的数一定是小于等于n 的
            if(count == n) ret.push_back(left);
            right++;
        }
        return ret;
    }

题 7 串联所有单词的子串:

30. 串联所有单词的子串 - 力扣(LeetCode)

题干:

数据范围:

例子:

思考:

结合题干我们可以得知,s 中的字符均是words 中所有字符串以任意顺序拼接而成的;其实这道题跟上一道题很像,只不过上道题是处理字符,而本题是处理字符串;

可见本题和上一题的思路大差不差,不过是在细节层面有所区别;

解法:同向双指针 + 哈希表

在上题中,因为是对字符进行操作,所以其中的哈希表可以用数组实现也可以用容器unordered_map 来实现哈希表,但是本题中是要对字符串进行处理,所以哈希表最好就不要使用数组实现,而是用容器unordered_map 来实现;

因为words 中的字符串的长度都一样,而每一次移动需要指向下一个字符串,也就是说同向双指针的移动不能是一个位置一个位置地移动,而其一次移动地距离由words 中字符串的长度决定;算法逻辑跟上一题如出一辙,此处就不再过多赘述;

还需要注意的是,s 字符串中的划分不会像我们上图那样words 中的字符串长度为多长其余的单词也为多长,此处为了不漏,需要在外层再套一个循环:从哪个位置开始向后找,由words 中字符串的长度决定;

参考代码:

    vector<int> findSubstring(string s, vector<string>& words) 
    {
        int n = s.size() , m =  words.size() , len = words[0].size();
        vector<int> ret;
        unordered_map<string,int> hash1;
        for(auto&e: words) hash1[e]++;
        //执行m次
        for(int i = 0; i<len;i++)
        {
            int left = i, right = i , count  = 0;
            unordered_map<string,int> hash2;
            //滑动窗口
            while(right <= n - len)//此处是一个细节
            {
                //入窗口
                string in = s.substr(right , len);
                hash2[in]++;
                //维护count
                if(hash1.count(in) && hash2[in] <= hash1[in]) count++;
                //判断 - 出窗口
                if(right-left+1 > m*len) 
                {
                    string out = s.substr(left , len);
                    //出窗口前维护count
                    if(hash1.count(out) && hash2[out] <= hash1[out]) count--;
                    hash2[out]--;
                    left+=len;
                }
                //更新数据
                if(count == m) ret.push_back(left);
                right+=len;
            }
        }
        return ret;
    }

题8 最小覆盖子串 :

76. 最小覆盖子串 - 力扣(LeetCode)

题干:

数据范围:

例子:

思考:

本题跟题6也很相似,只不过本题求的是当窗口中均包含了 t 中的字符的时候,窗口中的最小长度,并且返回窗口中的字符;此处可以用两个变量来记录,一个记录窗口中字符串的最小长度,一个来记录最小长度的内容或者是一个记录窗口中字符串最小长度的起始下标,一个记录窗口中字符串的最小长度;

如何才能让窗口中的字符个数最小?当然窗口的最左边和最右边都是所要求的字符(t 中的字符),那么这就是出窗口的判断,判断left 指向的是否是t 中的字符;同样地,与题6相似,需要用到hash 表来统计窗口中、t 中的字符,并且需要一个变量来维护窗口中有效字符的个数;

完整逻辑讲解:

解法一:暴力解法+哈希表

枚举出所有子串的情况,然后后找到符合题干的最短的子串返回即可;同样的,想要知道枚举出来的子串是否覆盖t 中的字符,与题6一样,需要借助于哈希表来实现;

我们需要优化暴力枚举的过程:

我们定义了两个指针left right , right 进行查找,当区间[left,right] 中的字符串符合题干规定的时候,就可以计算此区间的长度;然后left ++,right 回到left 指向的地方,right 继续往后找……这是暴力枚举的做法;我们需要思考的是,right 是否有必要重新回到left 指向的地方?

没必要;因为我们需要维护[left,right] 之中包含所有t 中的字符就行了;所以我们就需要讨论,left自增之后,[left,right] 中的情况,如下:

显然,此处的优化就是用滑动窗口来解决;在实现代码之前,我们需要弄清楚,入窗口、出窗口、更新数据如何操作;

解法二:同向双指针(滑动窗口) + 哈希表

因为s 与 t 中的字符全为英文字符,所以我们哈希表的实现可以是用 大小为128 的数组实现,也可以是用容器unordered_map 来实现; 

首先是要将 t 中的字符全部放入hash1 之中,然后是入窗口,将right 指向的字符放入hash2 之中。按照前面几道题的做题逻辑,此时我们应该判断是否要出窗口。如何出窗口呢?当[left,right] 区间中给的字符符合要求,暴力枚举的思想是:left++,right 回到left 指向的地方;但是符合要求了不统计就直接left++?显然本题就需要先更新数据然后再判断是否要出窗口;

还需要注意的一个点是,想要判断hash2 中是否都有hsah1 中的字符与个数时,无论是用数组实现的哈希表还是利用容器unordered_map 实现的哈希表均要一个遍历比较,有点消耗效率;此处可以参考前几道题用过的策略来进行优化:利用变量来记录[left,right] 中有效数据的个数;

思路总结:

参考代码1:

此处使用unordered_map 实现的

    string minWindow(string s, string t) 
    {
         int n = s.size() , m = t.size();
         unordered_map<char , int> hash1,hash2;
         for(auto ch : t) hash1[ch]++;
         int left = 0, right = 0, count = 0 , retlen = INT_MAX, begin = -1;
         while(right < n)
         {
            //入窗口
            char in = s[right];
            hash2[in]++;
            //统计窗口中有效数据的个数
            if(hash1[in] && hash2[in] <= hash1[in]) count++;
            //更新数据
            while(count == m)
            {
                int len = right - left +1;
                if(len < retlen)
                {
                    retlen = len;
                    begin = left;
                }
                char out  = s[left];
                //维护count
                if(hash1[out] && hash2[out]<=hash1[out]) count--;
                hash2[out]--;
                left++;
            }
            right++;
         }
         if(begin == -1) return "";//直接返回空字符串
         return s.substr(begin , retlen);
    }

参考代码2:

代码二的哈希表就用数组实现并且简化代码的书写:

    string minWindow(string s, string t) 
    {
         int n = s.size() , m = t.size();
         int hash1[128] = {0};
         int hash2[128] = {0};
         for(auto ch : t) hash1[ch]++;
         int left = 0, right = 0, count = 0 , retlen = INT_MAX, begin = -1;
         while(right < n)
         {
            //入窗口
            char in = s[right];
            //统计窗口中有效数据的个数
            if(hash1[in] && ++hash2[in] <= hash1[in]) count++;
            //更新数据
            while(count == m)
            {
                int len = right - left +1;
                if(len < retlen)
                {
                    retlen = len;
                    begin = left;
                }
                char out  = s[left++];
                //维护count
                if(hash1[out] && hash2[out]-- <= hash1[out]) count--;
            }
            right++;
         }
         if(begin == -1) return "";//直接返回空字符串
         return s.substr(begin , retlen);
    }

总结

既然看到这里了,那就把这些题再做一遍吧~

  1. 209. 长度最小的子数组
  2. 3. 无重复字符的最长子串
  3. 1004. 最大连续1的个数 III
  4. 1658. 将 x 减到 0 的最小操作数
  5. 904. 水果成篮
  6. 438. 找到字符串中所有字母异位词
  7. 30. 串联所有单词的子串
  8. 76. 最小覆盖子串

滑动窗口,无非就是利用两个同向双指针,根据题干的要求设置入窗口的条件、出窗口的条件以及什么时候更新结果;需要注意的是,更新结果的地方是不确定的,可能是在入窗口后更新结果,也有可能是在出窗口之后才更新结果,需要根据具体的题意定夺;

LeetCode 100道题目和答案(面试必备)(一) 给你一个字符串 s,由若干单词组成,单词之间用空格隔开。返回字符串中最后一个单词的长度。如果不存在最后一个单词,请返回 0单词 是指仅由字母组成、不包含任何空格字符的最大子字符串标签:字符串遍历从字符串末尾开始向前遍历,其中主要有两种情况第一种情况,以字符串"Hello World"为例,从后向前遍历直到遍历到头或者遇到空格为止,即为最后一个单词"World"的长度5。 阅读详情

相关推荐

力扣hot100二刷——哈希、双指针、滑动窗口

第二次刷题不在idea写代码,而是直接在leetcode网站上写,“逼”自己掌握常用的函数。

weixin_49426115的博客 790

Leetcode各种题型题目+思路+代码(共176道题及答案)

文章目录 第一章:Leetcode 每日很多题 1、Leetcode-1047 删除字符串中的所有相邻重复项 2、剑指 Offer 53 - I. 在排序数组中查找数字 I 3、Leetcode704:二分查找 4、 Leetcode 227:基本计算器II 5、leetcode 224:基本计算器(带括号的计算) 6、Leetcode 15:三数之和:排序+双指针 7、剑指 offer 38.字符串的排列 8、Leetcode409:最长回文串 9、Leetcode 331:验证二叉树的前序序列化 10、

muli522的博客 4万+

力扣239 - 滑动窗口的最大值【单调队列的原理】

对应力扣239 - 滑动窗口的最大值,带你搞懂单调队列的实现原理

做技术人 · 产优质博客 · 找好工作 1396

Leetcode 算法题合集

Leetcode 算法

19年的墨先生的博客 3243

LeetCode数据库题目汇总一(附答案)

表: `Queue````person_id 是这个表的主键。该表展示了所有等待电梯的人的信息。表中 person_id 和 turn 列将包含从 1 到 n 的所有数字,其中 n 是表中的行数。```电梯最大载重量为 **1000**。写一条 SQL 查询语句查找最后一个能进入电梯且不超过重量限制的 `person_name`。题目确保队列中第一位的人可以进入电梯。查询结果如下所示 :```Queue 表。

悦分享 1650

VScode - 从入门到精通:高效开发环境搭建指南

本文是一份全面的VSCode高效开发环境搭建指南。从选择理由、安装配置、核心插件推荐到个性化设置与高效技巧,详细讲解了如何将这款轻量级编辑器武装成强大的开发工具。重点介绍了GitLens、Prettier、Live Server等必备插件,以及通过用户设置、代码片段和快捷键打造专属高效工作流的方法,帮助开发者从入门到精通。

weixin_27734811的博客 426

力扣(leetcode)题目总结——滑动窗口篇

本系列文章初衷是为了按类别整理出力扣(leetcode)最经典题目,一共100多道题,每道题都给出了非常详细的解题思路、算法步骤、代码实现。因为力扣题目顺序是随机的,并没有按照算法分类,导致同一类型的算法强化训练不够。所以本系列文章就是来帮你完成算法分类,针对每种算法做强化训练,保证让你以后遇到题目直接秒杀。本篇文章主要是针对滑动窗口相关的算法题,一次性帮你搞定所有滑动窗口题!

weixin_46571171的博客 1246

小米手机Magisk解锁与Root完整指南:从Bootloader到模块管理

Android系统Root权限获取是设备深度定制的核心技术之一,其核心原理在于通过修改系统启动流程获取超级用户权限。Systemless Root技术通过动态挂载修改,在不触碰系统分区的前提下实现功能注入,既保证了系统完整性,又能绕过完整性检测。这一技术为设备带来了极高的可定制性,用户可以通过模块化方式增强系统功能、修改UI界面或启用隐藏特性。在小米手机生态中,由于官方提供了完整的Bootloader解锁通道,结合Magisk的无系统修改Root方案,使得安全可控的深度定制成为可能。本文聚焦于Bootloa

weixin_29164185的博客 334

【力扣】滑动窗口专题

如果我们想做出来定长滑动窗口的题目有两个必要条件,首先要辨别是否可以运用定长滑窗,其次要知道定长滑窗的解题思路辨别定长滑窗:题目中要求“一段连续长度k中的xxx”(即子数组,子字符串)知道定长滑窗解题套路:入,更新,出(在第一题后边)滑动窗口是双指针的一种特殊形式,通常用于解决**子数组(子字符串)**的问题。滑动窗口的核心思想是维护一个窗口(由两个指针表示),通过移动窗口的左右边界来满足特定条件。定长滑动窗口步骤为入(枚举右端点),更新,出。

weixin_45467593的博客 1733

告别QWebEngineView!用QtLocation+SQLite打造离线地图应用(附完整源码)

本文详细介绍了如何利用QtLocation模块与SQLite数据库构建高性能离线地图引擎,解决传统QWebEngineView方案在网络依赖、内存占用和定制化方面的不足。通过多级缓存机制、异步写入优化和纹理压缩技术,实现工业级应用的稳定运行和高效渲染,特别适合车载导航和野外勘探等场景。

weixin_30431445的博客 363

86 arduino 电机yl_(八)arduino入门:直流电机控制

一、本节介绍在本实验中,您将学习如何使用驱动芯片L293D和SunFounder Uno板控制小型直流(DC)电机的方向和速度。为了使初学者更容易,我们将让直流电机左右旋转,自动加速和减速。二、材料准备1 *小型直流电机1 * L293D1 * Arduino Uno板1 *面包板1 * USB数据线杜邦线三、原理讲解L293D这是一个非常实用的芯片,可以独立控制两台直流电机。在这个实验中,只有一...

weixin_29163857的博客 3568

【leetcode】滑动窗口专题

“滑动窗口”算法思想相关题目

weixin_69380220的博客 1766

PSF(点扩散函数)与去卷积算法消除图像模糊

本文旨在总结图像处理中使用去卷积的传统方法来进行图像去模糊的相关知识。

m0_53607446的博客 6015

leetcode滑动窗口问题

想成功先发疯,不顾一切向前冲。

m0_73883551的博客 2459

Python量化投资——mplfinance实现全功能动态交互式K线图(蜡烛图)【源码+详解】

特别鸣谢:@szFoxtech 同学热心提供了通过键盘操作平移和缩放K线图的代码!!在我的另一篇文章《七行代码利用tushare和mplfinance生成K线图》中,我介绍了两个非常好用的python库,结合起来可以非常方便容易地生成股票的K线图,对于使用python进行量化投资研究的朋友可谓是必备良方。如下图所示,仅仅几行代码,就能生成下面这张K线图:不过,仅仅使用七行代码生成的K线图,虽然看上去也像那么回事了,但是对于真正需要使用K线图作为研究工具或者可视化工具的朋友们来说,是远远不够的。在我看来,至少

m0_67390379的博客 9836

YOLOv13安装教程 手把手教你融合空间注意力机制(SAB)的RAB卷积模块 自动“聚焦”重要的特征 map指标提升8.96,准确率提升3.56

本文提出了一种改进的YOLOv13目标检测模型,通过引入RAB(残差注意力模块)显著提升了检测性能。实验结果显示,添加RAB模块后,mAP指标提升了8.96,准确率提高了3.56%。文章详细介绍了RAB模块的实现方法:1)采用多级残差连接增强特征提取能力;2)结合空间注意力机制(SAB)自动聚焦关键区域;3)通过1×1卷积实现通道维度压缩与恢复。同时提供了完整的模型移植方案,包括配置文件修改、任务处理代码调整以及模块实现细节,为YOLO系列模型的性能优化提供了有效参考。

FJN110的博客 647

【滑动窗口】算法总结/力扣题目整理

力扣链接给你一个数组 nums 和一个值 val,你需要原地移除所有数值等于 val 的元素。元素的顺序可能发生改变。然后返回 nums 中与 val 不同的元素的数量。假设 nums 中不等于 val 的元素数量为 k,要通过此题,您需要执行以下操作:更改 nums 数组,使 nums 的前 k 个元素包含不等于 val 的元素。nums 的其余元素和 nums 的大小并不重要。返回 k。

Mr_StrangerN的博客 1956

【PowerBI专栏】PowerBI导入MYSQL数据库

本文介绍了在PowerBI中连接MySQL数据库的方法。首先需要下载并安装MySQL官方.NET连接驱动(推荐8.4.0版本),安装完成后重启PowerBI。连接时需填写服务器IP和数据库名称等必填参数。文章详细说明了连接配置步骤,包括账户设置、数据表选择以及可能遇到的数据格式转换问题处理。最后指导用户完成数据清洗后进入PowerPivot进行后续计算。特别提醒最新9.4版本可能存在兼容性问题,建议使用稳定的8.4版本连接器。

技术与管理的平衡木- 692

掌握这15种模式后,力扣(LeetCode)不再难

在掌握这15种模式之前,力扣(LeetCode)对我来说一直很难。

硅基创想家的博客 4324

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

【leetcode C++】滑动窗口

leetcode LCR 008. 长度最小的子数组 和 LCR 016. 无重复字符的最长子串 C++讲解

2301_79789645的博客 1579

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

【滑动窗口】力扣239.滑动窗口最大值

滑动窗口——窗口内的最大值

weixin_46879314的博客 1281

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

力扣100及题解 滑动窗口&子串

要找的子数组的和是 k,要找的子数组的前缀和应该是 sum - k。前缀和ps是数组中从第一个元素开始,到当前元素为止所有元素的和。适用于求子数组或子串的最大值、最小值或满足某些条件的长度等。在给定字符串中,寻找没有重复字符的最长子串。子串:连续的字符片段。给定一个数组,找到所有长度为。所有字符的最短子串。的滑动窗口的最大值。

hiahiakk的博客 1158

力扣 滑动窗口题目总结

其实就是一个队列,比如例题中的 abcabcbb,进入这个队列(窗口)为 abc 满足题目要求,当再进入 a,队列变成了 abca,这时候不满足要求。所以,我们要移动这个队列!

qq_40222433的博客 1206

力扣hot100-->滑动窗口、贪心

在这里,我们一同探索代码的奥秘,感受技术的魅力 ✨。👉📌🛠️💡。

Dong雨的博客 1913

力扣滑动窗口总结java版(直接学模板+逐行注释解析!)

这个题我们只需要换一个想法,看示例1,用x减去最后的2,3可以得到结果,其实也可以把前面的[1,1,4]看成一个滑动窗口,这个滑动窗口的和为数组nums全部元素的和减x的值。然后套模板去滑动窗口,如果发现word1单词的哈希数组值是负的,就说明是我们所需要的,我们的“欠债”就减一,“欠债”为debt,初始化为word2.length()。此题重点是无限追加,其实不难发现,我们只需要讨论一次追加即可,之后的每次追加效果都相同,只需要记录原数组的和total,之后用target去模total即可。

weixin_51675784的博客 1810

力扣刷题总结笔记——滑动窗口

我们平常做题的时候只要看到是和子串相关的题目我们就要第一时间想到是不是滑动窗口题目,一般的子串都是用和双指针进行解决,还有一个前缀和。

weixin_53432918的博客 819
上一篇: VS小技巧:如何在一个项目中添加其他项目
下一篇: C++ - 类和对象 #取地址运算符重载 #构造函数 #类型转换 #友元 #static 成员 #内部类 #匿名对象 #对象拷贝时编译器的优化
秦少游在淮海
博客等级 码龄3年 1071粉丝 88原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值