76. 最小覆盖子串

题目

给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 "" 。

注意:1.如果 s 中存在这样的子串,我们保证它是唯一的答案。2.最小子串中不仅需要包含t中出现的字符,字符出现的次数也有要求
 
示例 1:

输入:s = "ADOBECODEBANC", t = "ABC"
输出:"BANC"

示例 2:

输入:s = "aa", t = "aa"
输出:"aa"

滑动窗口法

很显然要使用滑动窗口法,但关键的问题是如何得知当前子串是否包含了t中所有字符
可以使用一个计数器cnt:遍历right时HashMap 中的 value 减一,如果减1后仍大于等于0说明该字符在t中出现过,cnt 自增1;当cnt等于t长度时说明已经包含了t中所有字符,此时left右移,遍历left时HashMap 中的 value 加一,如果加1后大于0说明移出掉的是t中出现的字符,cnt自减1。

具体步骤:
(1)先扫描一遍T,把对应的字符及其出现的次数存到 HashMap 中。
(2)然后开始遍历S,就把遍历到的字母对应的 HashMap 中的 value 减一,如果减1后仍大于等于0,cnt 自增1。
(3)如果 cnt 等于T串长度时,开始循环,纪录一个字串并更新最小字串值。然后将子窗口的左边界向右移,如果某个移除掉的字母是T串中不可缺少的字母,那么 cnt 自减1,表示此时T串并没有完全匹配。

    public String minWindow(String s, String t) {
        if(s.length()<t.length()) return "";
        int left=0,right=0,sLen=s.length(),tLen=t.length(),cnt=0,minLen=Integer.MAX_VALUE,l=left,r=right;
        int[] charCount=new int[128];
        for(int i=0;i<tLen;++i) charCount[t.charAt(i)]++;
        while(right<sLen){
            //如果减1后的映射值仍大于等于0,说明当前遍历到的字母是T串中的字母,cnt自增1
            if(--charCount[s.charAt(right++)]>=0) cnt++;
            while(cnt==tLen){
                if(minLen>right-left){
                    minLen=right-left;
                    l=left;
                    r=right;
                }
                //如果加1后的值大于0了,说明此时少了一个T中的字母,那么 cnt 值就要减1
                if(++charCount[s.charAt(left)]>0) cnt--;
                left++;
            }
        }
        return s.substring(l,r);
    }

LeetCode 76.最小覆盖子串

posted @ 2021-05-10 19:24  归鸿唱晚  阅读(79)  评论(0编辑  收藏  举报