滑动窗口力扣总结

一、答题模板

第一步:根据题目设置变量
例如:数组和sum、最大长度等
第二步:确定窗口开始位置start和结束位置end
第三步:判断条件,两种情况

  • 窗口长度固定:以窗口长度为判断依据
  • 窗口长度可变:根据题目中的要求判断

第四步:更新变量,两种情况

  • 窗口长度固定:start右移,维持窗口长度不变
  • 窗口长度可变:start右移,直到窗口符合条件为止

二、力扣题

(1)窗口长度可变

a.元素不能重复

3. 无重复字符的最长子串

  • step1:设置变量,不重复元素,维护变量map,key为不重复字符,value为key出现的最后一次下标
  • step2:start从0 开始,循环end
  • step3:窗口长度可变,判断条件为map中有没有s.charAt(end)
  • step4:map中有,则更新start。再计算最大长度,并将s.charAt(end)放入map中,map中有则覆盖,没有则直接放入
class Solution {
    public int lengthOfLongestSubstring(String s) {
        Map<Character,Integer> map=new HashMap<>();
        int start=0;
        int res=0;
        for(int end=0;end<s.length();end++){
            char c=s.charAt(end);
            if(map.containsKey(c)){
                start=Math.max(start,map.get(c)+1);
            }
            res=Math.max(res,end-start+1);
            map.put(c,end);
        }
        return res;
    }
}

1695. 删除子数组的最大得分

  • step1:设置变量,不重复元素,维护变量map,key为不重复字符,value为key出现的最后一次下标
  • step2:start从0 开始,循环end
  • step3:窗口长度可变,判断条件为map中有没有nums[end]
  • step4:map中有,则更新start。与上题不同的是,本题要维护变量temp,来记录start的位置,便于在更新start的时候,可以从sum中减去temp到start位置的和
class Solution {
    public int maximumUniqueSubarray(int[] nums) {
        Map<Integer,Integer> map=new HashMap<>();
        int start=0;
        int sum=0;
        int res=0;
        for(int end=0;end<nums.length;end++){
            if(map.containsKey(nums[end])){
                int temp=start;
                start=Math.max(start,map.get(nums[end])+1);
                while(temp!=start){
                    sum-=nums[temp++];
                }
            }
            sum+=nums[end];
            res=Math.max(sum,res);
            map.put(nums[end],end);
        }
        return res;
    }
}

b.和问题

209. 长度最小的子数组

  • step1:设置变量,维护变量sum
  • step2:start从0 开始,循环end
  • step3:窗口长度可变,判断条件为sum与target的比较
  • step4:sum>=target,则更新start和res。要找最小的数组长度,所以在满足条件的基础上,尽可能减少长度,更新start和sum。满足条件时才能更新res
class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int start=0;
        int res=Integer.MAX_VALUE;
        int sum=0;
        for(int end=0;end<nums.length;end++){
            sum+=nums[end];
            while(sum>=target){
                res=Math.min(res,end-start+1);
                sum-=nums[start++];
            }
        }
        return res==Integer.MAX_VALUE?0:res;
    }
}

1695. 删除子数组的最大得分
与上题类似,但是要求元素不重复。那么需要维护变量map,并且在更新sum时,需要将更新前的start到更新后的start期间的值都减去。
1208. 尽可能使字符串相等

  • step1:设置变量,维护变量sum
  • step2:start从0 开始,循环end
  • step3:窗口长度可变,判断条件为sum与maxCost的比较
  • step4:sum>maxCost,则更新start和sum。要找最大长度,在不满足条件的时,更新start和sum以满足条件。满足条件后,更新res
class Solution {
    public int equalSubstring(String s, String t, int maxCost) {
        int start=0;
        int sum=0;
        int res=0;
        for(int end=0;end<s.length();end++){
            sum+=Math.abs(s.charAt(end)-t.charAt(end));
            while(sum>maxCost){
                sum-=Math.abs(s.charAt(start)-t.charAt(start));
                start++;
            }
            res=Math.max(res,end-start+1);
        }
        return res;
    }
}

c.其他

1004. 最大连续1的个数 III(重要)

  • step1:设置变量,维护变量res
  • step2:start从0 开始,循环end
  • step3:窗口长度可变,循环判断条件为k<0
  • step4:先end向前走,直到k<0,start开始收缩,收缩到k>=0,符合条件,再更新res的值
class Solution {
    public int longestOnes(int[] nums, int k) {
        int start=0;
        int res=0;
        for(int end=0;end<nums.length;end++){
            if(nums[end]==0){
                k--;
            }
            //收缩--》k<0时,左边一直收缩
            while(k<0){
                if(nums[start]==0) k++;
                start++;
            }
            res=Math.max(end-start+1,res);
        }
        return res;
    }
}

(2)窗口长度固定

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

  • step1:设置变量,维护变量count[]来记录p中出现的字母,以及次数
  • step2:start和end都从0 开始,用双指针进行循环。不能像之前用for循环end,因为当count[end]==0时,start开始收缩,与此同时,如果end右移,那么下次循环的长度还维持与本次循环的一样,无法通过end-start-1等于p的长度来判断是否为异位词
  • step3:窗口长度固定,判断条件为end-start+1与p.lengtha()的比较
  • step4:p中出现s.charAt(end),则更新end和count[],没出现则收缩。再根据长度再做判断
class Solution {
    public List<Integer> findAnagrams(String s, String p) {
        List<Integer> res=new ArrayList<>();
        int start=0,end=0;
        int[] count=new int[26];
        for(int i=0;i<p.length();i++){
            count[p.charAt(i)-'a']++;
        }
        while(end<s.length()){
            if(count[s.charAt(end)-'a']>0){
                count[s.charAt(end)-'a']--;
                if(end-start+1==p.length()){
                    res.add(start);
                }
                end++;
            }else{
                count[s.charAt(start)-'a']++;
                start++;
            }
        }
        return res;
    }
}

567. 字符串的排列
与上题类似

class Solution {
    public boolean checkInclusion(String s1, String s2) {
        int[] count=new int[128];
        for(int i=0;i<s1.length();i++){
            count[s1.charAt(i)-'a']++;
        }
        int start=0,end=0;
        while(end<s2.length()){
            if(count[s2.charAt(end)-'a']>0){
                count[s2.charAt(end++)-'a']--;
                if(end-start==s1.length()){
                    return true;
                }
            }else{
                count[s2.charAt(start++)-'a']++;
            }
        }
        return false;
    }
}

643. 子数组最大平均数 I
与209题类似

class Solution {
    //滑动窗口,固定长度
    public double findMaxAverage(int[] nums, int k) {
        double sum=0;
        int start=0;
        double res=Integer.MIN_VALUE;//不能设置为0,因为0和sum/k比较会一直是0,但是sum/k会有小于0的情况
        for(int end=0;end<nums.length;end++) {
            sum += nums[end];
            if (end - start + 1 == k) {
                res = Math.max(res, sum/k);
                sum-=nums[start++];
            }
        }
        return res;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值