刷题笔记13——滑动窗口

滑动窗口板子小结

  • 首先明确是两条字符串,一条不动,另一条扒在这条字符串上进行寻找,以一格一格遍历绝对可以搜到答案
  • 在开头位置写好小字符串的标准板,利用这个标准板来对窗口进行判断
  • 决定好窗口变不变,来修改内部while的情况
  • 有一些小策略可以帮助窗口滑动的更快,但是要保证每次滑动所有的记录都要匹配,最快的话是清零,不是的话不如还是挨个走,然后一个个清除
  • hash里边是put,list的时候是add,动态字符串是append
  • 为了方便记忆去搜了java命名规范
    • 对于类或者接口,类似于HashMap, ArrayList等,首字母必须要大小
    • 对于方法,类似于getOrDefault(), toCharArray(),驼峰命名
    • 对于常量,Integer.MAX_VALUE;就要全部大写

76. 最小覆盖子串

  • 虽然在纸上推导出来窗口的大概滑动情况,但是比较难的是代码中的细枝末节
  • 通常用左闭右开的窗口,那么最开始停在[0,0)表示滑动窗口还没有元素,为了避免多余元素的判断比如0位置,所以就直接这样进入while循环,以空的滑动进入while循环,说明当前是加入一个判断一个的情况,加入当前right元素进去,right++,right一直停在下一个需要判断的元素上
  • 还有一个我自己的想法就是,每次都是等left移动到一个不可行解的情况下,才开始移动right,那么可以认为[0,0)就是从0开始的一个不可行解
  • 掌握思想即可,出现频率不高
class Solution {
    public String minWindow(String s, String t) {
        Map<Character, Integer> need = new HashMap<>();
        Map<Character,Integer> window = new HashMap<>();
        char[] tt = t.toCharArray();

        for (int i=0;i<t.length();i++){
            char c = tt[i];
            need.put(c,need.getOrDefault(c,0)+1);
        }


        int left = 0;
        int right= 0;
        int start = 0;
        int len = Integer.MAX_VALUE;
        int valid = 0;
        
        while(right<s.length()){
            char c = s.charAt(right);
            right++;
            if(need.containsKey(c)){
                window.put(c,window.getOrDefault(c,0)+1);
                if(window.get(c).equals(need.get(c))){
                    valid++;
                }
            }

            while(valid == need.size()){
                if(right-left<len){
                    start = left;
                    len = right-left;
                }
                char d = s.charAt(left);
                left++;
                if(need.containsKey(d)){
                    if(window.get(d).equals(need.get(d)))
                        valid--;
                    window.put(d, window.get(d) - 1);
                }
            }
        }
        return len==Integer.MAX_VALUE? "":s.substring(start,start+len);
    }
}


567. 字符串的排列

  • 板子是通过何时移动left来维持一个固定长度的window
  • 我i最初的想法是对s2进行遍历,当长度达到了len不满足结果,就向右边挪动一格,在向右挪动的过程中如果发现不出现在s1中的元素,那么right++,left = right,我觉得我的方法更快一点,因为避免了不必要的挪动。
class Solution {
    public boolean checkInclusion(String s1, String s2) {
        HashMap<Character, Integer> need= new HashMap<>();
        HashMap<Character, Integer> window = new HashMap<>();
        for(char c:s1.toCharArray()){
            need.put(c,need.getOrDefault(c,0)+1);
        }

        int valid = 0;
        int left = 0;
        int right = 0;

        while(right<s2.length()){
            char c = s2.charAt(right);
            right++;
            if (need.containsKey(c)){
                window.put(c,window.getOrDefault(c,0)+1);
                if(window.get(c).equals(need.get(c))){
                    valid++;
                }
            }

            while(right-left>=s1.length()){
                if(valid==need.size()){
                    return true;
                }
                char d = s2.charAt(left);
                left++;
                if (need.containsKey(d)){
                    if(window.get(d).equals(need.get(d)))
                        valid--;
                    window.put(d, window.getOrDefault(d, 0) - 1);
            }
            }
        }
        return false;
    }
}
  • 突然发现稍微改动就是我的思路,稍微快2ms
  • HashMap.clear()
class Solution {
    public boolean checkInclusion(String s1, String s2) {
        HashMap<Character, Integer> need= new HashMap<>();
        HashMap<Character, Integer> window = new HashMap<>();
        for(char c:s1.toCharArray()){
            need.put(c,need.getOrDefault(c,0)+1);
        }

        int valid = 0;
        int left = 0;
        int right = 0;

        while(right<s2.length()){
            char c = s2.charAt(right);
            right++;
            if (need.containsKey(c)){
                window.put(c,window.getOrDefault(c,0)+1);
                if(window.get(c).equals(need.get(c))){
                    valid++;
                }
            }
            else{
                left=right;
                window.clear();
                valid=0;

            }

            while(right-left>=s1.length()){
                if(valid==need.size()){
                    return true;
                }
                char d = s2.charAt(left);
                left++;
                if (need.containsKey(d)){
                    if(window.get(d).equals(need.get(d)))
                        valid--;
                    window.put(d, window.getOrDefault(d, 0) - 1);
            }
            }
        }
        return false;
    }
}

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

  • 稍微修改一下输出即可
  • 滑动窗口问题中是通过内while来控制窗口的长度
//像这种情况就是,一直会保持窗口的长度为s.length
while(right-left>=s1.length())
//像这种情况就是,一直会向右探索,直到找到一个满足条件的,left才会开始向右走
while(valid == need.size())
class Solution {
    public List<Integer> findAnagrams(String s2, String s1) {
        List<Integer> res = new ArrayList<Integer>();
        HashMap<Character, Integer> need= new HashMap<>();
        HashMap<Character, Integer> window = new HashMap<>();
        for(char c:s1.toCharArray()){
            need.put(c,need.getOrDefault(c,0)+1);
        }

        int valid = 0;
        int left = 0;
        int right = 0;

        while(right<s2.length()){
            char c = s2.charAt(right);
            right++;
            if (need.containsKey(c)){
                window.put(c,window.getOrDefault(c,0)+1);
                if(window.get(c).equals(need.get(c))){
                    valid++;
                }
            }
            else{
                left=right;
                window.clear();
                valid=0;

            }

            while(right-left>=s1.length()){
                if(valid==need.size()){
                    res.add(left);
                }
                char d = s2.charAt(left);
                left++;
                if (need.containsKey(d)){
                    if(window.get(d).equals(need.get(d)))
                        valid--;
                    window.put(d, window.getOrDefault(d, 0) - 1);
            }
            }
        }
        return res;
    }
}

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

  • right是一定要进去的,不需要额外的判断,直接放进去
class Solution {
    public int lengthOfLongestSubstring(String s) {
        Map<Character, Integer> window = new HashMap<>();
        int left = 0;
        int right = 0;
        int len = 0;

        while(right<s.length()){
            char c = s.charAt(right);
            window.put(c, window.getOrDefault(c,0)+1);
            right++;
            
            while(window.get(c)>1){
                char d = s.charAt(left);
                window.put(d, window.getOrDefault(d,0)-1);
                left++;
            }
            len = Math.max(len, right-left);
        }
        return len;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值