【双指针】最小覆盖子串(滑动窗口)(medium)

若两个指针指向同一数组,遍历方向相同且不会相交,则也称为滑动窗口(两个指针包围的区域即为当前的窗口),经常用于区间搜索

leetcode 76最小覆盖子串
在这里插入图片描述
思路:
使用滑动窗口方法求解,即两个指针 l l l 和 r 都是从最左端向最右端移动,且 l l l的位置一定在r 的左边或重合。l和j窗口内包含的字符全涵盖t中的字符,则符合要求,记下此时窗口长度r- l l l+1。从符合条件的长度中找出最小长度即可。
step1: l和r都指向字符串开头。
step2: 不断右移r,直到窗口内包含了t中所有字符,记录下此次窗口长度。
step3: 左移 l l l,判断移除的字符是否在t字符串内,若在,则继续右移l(step2),若不在,则记录此时窗口长度,并判断是不是当前最小长度(若是,则更新最小长度),继续左移l。

考虑到t中会有重复字符,所以使用map来记录t中的字符及其出现的个数。
因此,判断窗口内的字符是否都涵盖了t中所有字符串,也需要使用map来记录窗口内的字符及其个数。t中某字符出现的次数与窗口中出现次数一致,且t中字符种类个数(e.g. “abadac”为4个字符种类)与窗口中字符种类个数一致时,即认为窗口全涵盖了t中字符。
右移指针 l l l时,窗口中字符要做相应变化,且要判断t中是否含有从窗口中移除的字符,若没有,则无操作;若有,则需要比较该字符在窗口中的个数与t中的个数,若一致,则移除该字符后,窗口不满足全涵盖t。若不一致(只会是大于等于,因为只有窗口全涵盖t时才会让l右移),则不操作。

class Solution {
    public String minWindow(String s, String t) {
        //将要覆盖的字符串放到map中并记录每个字母出现的次数。
        HashMap<Character,Integer> covered = new HashMap<>();
        for(char ch:t.toCharArray()){
            covered.put(ch,covered.getOrDefault(ch,0)+1);
        }
        //将窗口内的字符串放到map中并记录每个字母出现的次数。
        HashMap<Character,Integer> window = new HashMap<>();
        int left=0,right=0;//滑动窗口的左右指针
        int len = Integer.MAX_VALUE;
        int valid=0;//记录窗口中涵盖的t中字符串的个数(t中重复字符算一个)
        int start=0;//子路最小子串的起始位置
        //滑动部分逻辑
        while(right<s.length()){
            char c =s.charAt(right);
            right++;
            //右指针不断右移,只要有符合的字符valid就++,且该符合的字符放入到window中,并记录出现次数
            if(covered.containsKey(c)){
                window.put(c,window.getOrDefault(c,0)+1);
                if(window.get(c).equals(covered.get(c))){
                    valid++;
                }
            }
            //当 当前窗口字符串 涵盖 t中所有字符 时,记录长度,左指针右移
            while(valid==covered.size()){
                //记录当前窗口的长度
                if(right-left<len){
                    start=left;
                    len=right-left;
                }
                char d = s.charAt(left);//即将移除出窗口的字符
                //左指针右移
                left++;
                //若t中包含移除出窗口的字符d
                if(covered.containsKey(d)){
                    //只有当窗口内字符d的数量等于字符串t中字符d的数量时,valid--
                    //当窗口内字符d的数量大于字符串t中字符d的数量时,valid不用改动,
                    //因为移除字符d后仍满足窗口内字符串全包含t
                    if(window.get(d).equals(covered.get(d))){
                        valid--;
                    }
                    
                    //若t中不包含字符d,即使窗口左指针右移,窗口中包含的字符也不用移除,因为没影响。
                    // window.put(d,window.getOrDefault(d,0)-1);
                }
                //因为窗口左指针右移了,所以window中的字符要作相应变化
                window.put(d,window.getOrDefault(d,0)-1);
            }
        }
        return len==Integer.MAX_VALUE?"":s.substring(start,start+len);

    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值