76. 最小覆盖子串(困难)

76. 最小覆盖子串

class Solution {
    public String minWindow(String s, String t) {
        //记录字符串当前s窗口中各字符的数量
        HashMap<Character, Integer> hs = new HashMap<>();
        //记录字符串t中各字符的数量
        HashMap<Character, Integer> ht = new HashMap<>();

        //先将ht填好
        for(int i = 0; i < t.length(); i ++)
            ht.put(t.charAt(i), ht.getOrDefault(t.charAt(i), 0) + 1);
        
       //count记录当前窗口中满足t字符串的字符个数(必需字符),len记录符合条件的字串长度(取最小)
       //!!!len不能等与s.length(),因为第4步的判断条件是len > i - j + 1,当s=t时没有输出
       int count = 0, len = s.length() + 1;
       String ans = "";

       //[i, j]为滑动窗口
       for(int i = 0, j = 0; i < s.length(); i ++){
            //1.窗口右移了,更新hs中s[i]的value
            hs.put(s.charAt(i), hs.getOrDefault(s.charAt(i), 0) + 1);

            /* 2.ht中有新增的s[i]字符,并且hs中s[i]字符的数量 <= ht中s[i]字符的数量
            *    表明窗口右移新增的字符s[i]是必需的,count++
            *    注意此处有=号,不是<。原因是第1步已经更新了hs中的值,if中并不是<之后增加hs中的值,此处需要=
            */
            if(ht.containsKey(s.charAt(i)) && hs.get(s.charAt(i)) <= ht.get(s.charAt(i))) 
                count ++;

            /* 3.移动窗口左边界,必需满足j < i(左边界 < 右边界)
            *    如果字符串t中不包含s[j]字符,直接移动左边界
            *    如果hs中s[j]的数量 > ht中s[j]的数量,也可以移动左边界
            *    格式为while(a && (b || c))
            */
            while(j < i && (!ht.containsKey(s.charAt(j)) || hs.get(s.charAt(j)) > ht.get(s.charAt(j)))){
                hs.put(s.charAt(j), hs.get(s.charAt(j)) - 1);
                // int tmp = hs.get(s.charAt(j)) - 1;
                // hs.put(s.charAt(j), tmp);
                j ++;
            }

            //4.必需字符达到了t的长度(条件满足),且长度比上次记录的小,更新数据
            if(count == t.length() && len > i - j + 1){
                len = i - j + 1;
                ans = s.substring(j, i + 1);
            }
       }
        return ans;
    }
}

 

posted @ 2021-10-29 23:34  星予  阅读(35)  评论(0编辑  收藏  举报