算法—滑动窗口

目录

🌿长度最小的子数组

🧊题目链接

🧊题目描述

🧊题目分析

🧊解题代码

🌿无重复字符的最长子串

🧊题目链接

🧊题目描述

🧊题目分析

🧊解题代码

🌿最大连续1的个数III

🧊题目链接

🧊题目描述

🧊题目分析

🧊解题代码

🌿将x减到0的最小操作数

🧊题目链接

🧊题目描述

🧊题目分析

🧊解题代码

🌿水果成蓝

🧊题目链接

🧊题目描述

🧊题目分析

🧊解题代码

🌿找到字符串中所有字母异位词

🧊题目链接

🧊题目描述

🧊题目分析

🧊解题代码

🌿串联所有单词的子串

🧊题目链接

🧊题目描述

🧊题目分析

🧊解题代码

🌿最小覆盖子串

🧊题目链接

🧊题目描述

🧊题目分析

🧊解题代码


学了滑动窗口这个算法思想后,给我最大的感悟就是,我们要不断鞭策自己前行,像滑动窗口一样,要不断调整,维护,更新自己这个有巨大潜力的"窗口"!!!不断前行,不断反思,然后不断进步!!

🌿长度最小的子数组

🧊题目链接

https://leetcode.cn/problems/minimum-size-subarray-sum/

🧊题目描述

🧊题目分析

🧊解题代码

java 复制代码
class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int left=0,right=0;
        int mix=Integer.MAX_VALUE;//整形int最大值
        int sum=0;
        for(;right<nums.length;right++){
            sum+=nums[right];//进窗口
            while(sum>=target){//维护窗
                mix=Math.min(mix,right-left+1);//实时更新记录符合条件的最小长度
                sum-=nums[left++];
            }
        }
        return mix==Integer.MAX_VALUE?0:mix;//有可能mix没有改变,也就是0这种情况不要漏
    }
}

🌿无重复字符的最长子串

🧊题目链接

https://leetcode.cn/problems/longest-substring-without-repeating-characters/

🧊题目描述

🧊题目分析

我们这一个题和前一道题有点不同,虽然都是用到了滑动窗口,但这个题我们需要在每次维护窗口的时候之后,也就是出了维护窗口那个循环后,才更新结果而前一道题,是维护窗口的那个循环里,一开始就更新结果,两者本质区别就是这题维护的是使其窗口合法 ,而前一道题是将合法的窗口维护成不合法的窗口,但在每次维护成不合法的窗口之前,先更新结果,使right能不断右移,达到只要窗口一合法,就更新结果,然后使其维护成不合法的窗口,"驱动"这个窗口不断滑动!

哈哈,感觉全在将前一道题的知识,反正这两题相互相通,这也就是我为啥要提前一题的根本原因!!

🧊解题代码

java 复制代码
class Solution {
    public int lengthOfLongestSubstring(String s) {
        char[] ss=s.toCharArray();//String转char数组的方法
        int[] hash=new int[128];//模拟字符的哈希表
        int left=0,right=0;
        int ret=0;
        for(;right<ss.length;right++){
            hash[ss[right]]++; //进窗口
            while(hash[ss[right]]>1){//维护这个窗口始终不含重复字符
                hash[ss[left++]]--;//不符合就代表left那个值无用了,需要left右移
            }
         ret=Math.max(ret,right-left+1);//一趟下来,我们维护的这个窗口,没有重复字符,此时就需要更新一下结果
        }
        return ret;
    }
}

🌿最大连续1的个数III

🧊题目链接

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

🧊题目描述

🧊题目分析

这个和上一个题一样,都是维护窗口的合法性,最后才跟更新结果,也是和上一个题思路一致。

🧊解题代码

java 复制代码
class Solution {
    public int longestOnes(int[] nums, int k) {
        int left=0,right=0;
        int count=0;//统计窗口里0的个数
        int ret=0;//记录结果
        for(;right<nums.length;right++){
            if(nums[right]==0){//维护count
                count++;
            }
            while(count>k){//维护窗口的合法性
                if(nums[left]==0){
                    count--;
                }
                left++;
            }
            ret=Math.max(ret,right-left+1);//最后这个窗口就是合法的了,可以进行更新结果
        }
        return ret;
    }
}

🌿将x减到0的最小操作数

🧊题目链接

https://leetcode.cn/problems/minimum-operations-to-reduce-x-to-zero/

🧊题目描述

🧊题目分析

这个和上一个题一样,都是维护窗口的合法性,最后才跟更新结果 ,也是和上一个题思路一致,但就是运用了**"正难则反"**这个思维

🧊解题代码

java 复制代码
class Solution {
    public int minOperations(int[] nums, int x) {
        int target=0;//这个变量用来确定x与之对应的区间
        int count=0;//窗口的和
     for(int x1:nums){//先计算整个数组的和
        target+=x1;
     }
     target-=x;//然后最终确定好
     if(target<0){//这就是x的值超过整个数组和的值
        return -1;//那为啥要额外的拎出来写呢,那就是,在后面while(count>target)判断里,会始终满足,然后对我们
     }            //的正常的窗口有影响
     int max=-1;//记录符合条件的窗口的最大值
     int left=0,right=0;
     for(;right<nums.length;right++){
        count+=nums[right];//进窗口
        while(count>target){//出窗口,维护窗口
            count -= nums[left++];
        }
        if(count==target){//在不大于target的情况下,符合题意,那就更新max结果
            max=Math.max(max,right-left+1);
        }
     }
     return max==-1?-1:nums.length-max;//要注意下没有符合条件的x,也就是max始终没有改变,还是-1

    }
}

🌿水果成蓝

🧊题目链接

https://leetcode.cn/problems/fruit-into-baskets/

🧊题目描述

🧊题目分析

🧊解题代码

java 复制代码
class Solution {//其实整体代码逻辑不难,主要是看自己对HashMap常用方法熟不熟悉
    public int totalFruit(int[] fruits) {
        HashMap<Integer,Integer> hash=new HashMap<Integer,Integer>();//用hash表
        int left=0,right=0;
        int  ret=0;//记录收集水果的最大数目
        for(;right<fruits.length;right++){
            hash.put(fruits[right],hash.getOrDefault(fruits[right],0)+1);//进窗口,增操作
            while(hash.size()>2){//维护窗口
                if(hash.get(fruits[left])==1){// 减/删 去key对应的value
                    hash.remove(fruits[left]);
                }else{
                     hash.put(fruits[left],hash.get(fruits[left])-1);
                }
                left++;
            }
            if(hash.size()<=2){//符合条件,更新结果
                ret=Math.max(ret,right-left+1);
            }
        }
        return ret;
    }
}

🌿找到字符串中所有字母异位词

🧊题目链接

https://leetcode.cn/problems/find-all-anagrams-in-a-string/description/

🧊题目描述

🧊题目分析

🧊解题代码

java 复制代码
class Solution {
    public List<Integer> findAnagrams(String s, String p) {
        char[] s1=s.toCharArray();//用字符数组好操作些
        char[] s2=p.toCharArray();
        HashMap<Character,Integer> hash1=new HashMap<>();//表1记录字符串s的字符情况
        HashMap<Character,Integer> hash2=new HashMap<>();//表2记录字符串p的字符情况,但要先一次性遍历完
        List<Integer> list=new ArrayList<>();//list记录结果
        for(int i=0;i<p.length();i++){//先把hash2给记录好
            hash2.put(s2[i],hash2.getOrDefault(s2[i],0)+1);
        }
        int left=0,right=0;
        int count1=0;//用于记录有效字符个数,也就是hash2表里存在时,hash1表又要对其增加或删除时,就需要对count1进行维护,这也是后面判断是否是字符串p的字母异位词的关键!
        int n=p.length();//这个是字符串p的有效字符个数
        for(;right<s1.length;right++){
           
            hash1.put(s1[right],hash1.getOrDefault(s1[right],0)+1);//进窗口,维护hash1表
                if(hash1.get(s1[right])<=hash2.getOrDefault(s1[right],0)){//维护完hash1表之后,如果发现hash1对应的right值<=hash2对应的right值,就说明刚刚进入窗口的字符是字符串p的异位词的其中一个有效字符,就需要维护count1
                    count1++;
                }
                while((right-left+1)>n){//维护窗口大小
                //这里我没简短公共代码,主要是怕以后看不懂,给忘了
                //这下面代码就是出窗口+维护hash1表+维护count1
                    if(hash1.get(s1[left])<=hash2.getOrDefault(s1[left],0)){//为有效字符就维护hash1表+维护count1
                        if(hash1.get(s1[left])==1){//只剩下一个,那就remove清空
                            hash1.remove(s1[left]);
                        }else{//还有不止一个,那就-1
                            hash1.put(s1[left],hash1.get(s1[left])-1);
                        }
                        count1--;
                    }else{//不是有效字符,就只需要维护hash1表,逻辑和上面代码一致
                        if(hash1.get(s1[left])==1){
                            hash1.remove(s1[left]);
                        }else{
                            hash1.put(s1[left],hash1.get(s1[left])-1);
                        }
                    }
                    left++;//别忘了,left要更新
                }
                if(count1==n){//最后count1变量发挥作用,对符合条件的窗口进行add即可
                    list.add(left);
                }
        }
        return list;
    }
}

🌿串联所有单词的子串

🧊题目链接

https://leetcode.cn/problems/substring-with-concatenation-of-all-words/description/

🧊题目描述

🧊题目分析

🧊解题代码

java 复制代码
class Solution {
    public List<Integer> findSubstring(String s, String[] words) {
        HashMap<String,Integer> hash1=new HashMap<>();//记录字符串s的进窗口字符串信息
        HashMap<String,Integer> hash2=new HashMap<>();//记录字符串数组words的字符串的映射值
        for(int i=0;i<words.length;i++){//先把hash2给记录好
            hash2.put(words[i],hash2.getOrDefault(words[i],0)+1);
        }
        List<Integer> list=new ArrayList<>();//list记录结果
        int left=0,right=0;
        int count1=0;//有效字符串个数
        int n=words.length;//有效字符串个数
        int onlywords=words[0].length();//words中任意一子串长度计算
        for(;right<onlywords;right++){//外层循环,循环onlywords遍
            int flag=right;//保留记录原始right值,方便后面重置right值
            for(left=right;right+onlywords<=s.length();right+=onlywords){//这个终止条件自己画图理解
                 hash1.put(s.substring(right,right+onlywords),hash1.getOrDefault(s.substring(right,right+onlywords),0)+1);//进窗口,维护hash1表
                 if(hash1.get(s.substring(right,right+onlywords))<=hash2.getOrDefault(s.substring(right,right+onlywords),0)){//维护完hash1表之后,如果发现hash1对应的right值<=hash2对应的right值,就说明刚刚进入窗口的字符串是字符串数组words里其中一个有效字符串,就需要维护count1
                    count1++;
                }
                while((right-left+onlywords)>(n*onlywords)){
                    if(hash1.get(s.substring(left,left+onlywords))<=hash2.getOrDefault(s.substring(left,left+onlywords),0)){//为有效字符串就维护hash1表+维护count1
                        if(hash1.get(s.substring(left,left+onlywords))==1){//只剩下一个,那就remove清空
                            hash1.remove(s.substring(left,left+onlywords));
                        }else{//还有不止一个,那就-1
                            hash1.put(s.substring(left,left+onlywords),hash1.get(s.substring(left,left+onlywords))-1);
                        }
                        count1--;
                    }else{//不是有效字符串,就只需要维护hash1表,逻辑和上面代码一致
                        if(hash1.get(s.substring(left,left+onlywords))==1){
                            hash1.remove(s.substring(left,left+onlywords));
                        }else{
                            hash1.put(s.substring(left,left+onlywords),hash1.get(s.substring(left,left+onlywords))-1);
                        }
                    }
                    left+=onlywords;//别忘了,left要更新,是走一个字符串的长度,也就是onlywords
                }
                if(count1==n){//最后count1变量发挥作用,对符合条件的窗口进行add即可
                    list.add(left);
                }
                
            }
            hash1.clear();//一遍内循环走完,需要情况hash1表
            count1=0;//情况hash1表里对应的有效字符串的个数
            right=flag;//重置right值

        }
        return list;

    }
}

🌿最小覆盖子串

🧊题目链接

https://leetcode.cn/problems/minimum-window-substring/description/

🧊题目描述

🧊题目分析

🧊解题代码

java 复制代码
class Solution {
    public String minWindow(String s, String t) {
        char[] s1=s.toCharArray();
        char[] t1=t.toCharArray();

        HashMap<Character,Integer> hash1=new HashMap<>();
        HashMap<Character,Integer> hash2=new HashMap<>();//计算t字符串个数的映射值
        for(int i=0;i<t1.length;i++){//先把hash2给记录好
            hash2.put(t1[i],hash2.getOrDefault(t1[i],0)+1);
        }
        int left=0,right=0;
        int count=0;
        int min=Integer.MAX_VALUE;//先取整形int的最大值,因为找最小嘛
        int lastleft=-1;//-1对后面有帮助
        
        for(;right<s1.length;right++){
            hash1.put(s1[right],hash1.getOrDefault(s1[right],0)+1);//进窗口
            if(hash1.get(s1[right])<=hash2.getOrDefault(s1[right],0)){//维护有效字符个数count,超过了就不更新count了,反正多多益善嘛哈哈
                count++;
            }
            while(count==t1.length){//一当符合题意区间有了,就更新结果,并试图去寻找最短区间
                if((right-left+1)<min){//比原来的区间还小,那就更新结果
                    lastleft=left;
                    min=right-left+1;
                }
                if(hash1.get(s1[left])<=hash2.getOrDefault(s1[left],0)){//属于有效字符个数,出窗口会少个有效字符个数,所以需要维护count
                        if(hash1.get(s1[left])==1){//维护hash1
                        表的映射关系
                            hash1.remove(s1[left]);
                        }else{//维护hash1
                        表的映射关系
                            hash1.put(s1[left],hash1.get(s1[left])-1);
                        }
                        count--;//维护count    
                }else{//不属于有效字符个数,出窗口不会减少有效字符个数,所以不需要维护count
                        if(hash1.get(s1[left])==1){
                            hash1.remove(s1[left]);
                        }else{
                            hash1.put(s1[left],hash1.get(s1[left])-1);
                        }
                    }
                    left++;//最后逻辑完了,缩短区间
            }
        } 
        if(lastleft==-1){//lastleft还有初始值的-1,那就啥也没有最小覆盖子串这一说法,就是count始终达不到有效字符个数啊
                return new String();
            }
        return s.substring(lastleft,lastleft+min);
    }
}

完结喽🔎🌿🧊

相关推荐
风筝在晴天搁浅1 小时前
代码随想录 509.斐波那契数
数据结构·算法
落落落sss2 小时前
java实现排序
java·数据结构·算法
limenga1022 小时前
支持向量机(SVM)深度解析:理解最大间隔原理
算法·机器学习·支持向量机
coder江3 小时前
二分查找刷题总结
算法
坚持就完事了4 小时前
蓝桥杯中Python常用的库与模块
python·算法
立志成为大牛的小牛4 小时前
数据结构——四十四、平衡二叉树的删除操作(王道408)
数据结构·学习·程序人生·考研·算法
Suckerbin4 小时前
一次LeeCode刷题记录:接雨水
算法
Blossom.1184 小时前
RLHF的“炼狱“突围:从PPO到DPO的工业级对齐实战
大数据·人工智能·分布式·python·算法·机器学习·边缘计算
MobotStone6 小时前
从问答到决策:Agentic AI如何重新定义AI智能体的未来
人工智能·算法