Leetcode76. 最小覆盖子串

Leetcode76. 最小覆盖子串

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

注意:

对于 t 中重复字符,我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量。
如果 s 中存在这样的子串,我们保证它是唯一的答案。

示例 1:

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

示例 2:

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

示例 3:

输入: s = "a", t = "aa"
输出: ""
解释: t 中两个字符 'a' 均应包含在 s 的子串中,
因此没有符合条件的子字符串,返回空字符串。

方案:双指针
(滑动窗口) O ( n ) O(n) O(n)

过程如下:

1、遍历t字符串,用ht哈希表记录t字符串各个字符出现的次数。
Leetcode76. 最小覆盖子串_第1张图片
2、定义两个指针 j j j i i i j j j指针用于收缩窗口, i i i指针用于延伸窗口,则区间 [ j , i ] [j,i] [j,i]表示当前滑动窗口。首先让i和j指针都指向字符串s开头,然后枚举整个字符串s ,枚举过程中,不断增加 i i i使滑动窗口增大,相当于向右扩展滑动窗口。
Leetcode76. 最小覆盖子串_第2张图片

3、每次向右扩展滑动窗口一步,将s[i]加入滑动窗口中,而新加入了s[i],相当于滑动窗口维护的字符数加一,即hs[s[i]]++。
Leetcode76. 最小覆盖子串_第3张图片
4、对于新加入的字符 s [ i ] s[i] s[i],如果 h s [ s [ i ] ] < h t [ s [ i ] ] hs[s[i]] < ht[s[i]] hs[s[i]]<ht[s[i]],说明当前新加入的字符s[i]是必需的,且还未到达字符串 t t t所要求的数量。我们还需要事先定义一个 c n t cnt cnt变量, c n t cnt cnt维护的是s字符串 [ j , i ] [j,i] [j,i]区间中满足t字符串的元素的个数,记录相对应字符的总数。新加入的字符s[i]必需,则cnt++。

5、我们向右扩展滑动窗口的同时也不能忘记收缩滑动窗口。因此当 h s [ s [ j ] ] > h t [ s [ j ] hs[s[j]] > ht[s[j] hs[s[j]]>ht[s[j]时,说明hs哈希表中 s [ j ] s[j] s[j]的数量多于ht哈希表中s[j]的数量,此时我们就需要向右收缩滑动窗口,j++并使 h s [ s [ j ] ] − − hs[s[j]]-- hs[s[j]],即 h s [ s [ j + + ] ] − − hs[s[j ++ ]] -- hs[s[j++]]

6、当 c n t = = t . s i z e cnt == t.size cnt==t.size时,说明此时滑动窗口包含符串 t 的全部字符。我们重复上述过程找到最小窗口即为答案。

Leetcode76. 最小覆盖子串_第4张图片
时间复杂度分析: 两个指针都严格递增,最多移动 n n n 次,所以总时间复杂度是 O ( n ) O(n) O(n)

java代码:

public static String minWindow(String s, String t) {
        HashMap<Character, Integer> ht = new HashMap<>();
        HashMap<Character, Integer> hs = new HashMap<>();

        for (int i = 0; i < t.length(); i++) {
            ht.put(t.charAt(i), ht.getOrDefault(s.charAt(i), 0) + 1);
        }
        String ans = "";
        int len = Integer.MAX_VALUE, cnt = 0;
        int j = 0;
        for (int i = 0; i < s.length(); i++) {

            hs.put(s.charAt(i), hs.getOrDefault(s.charAt(i), 0) + 1);
            if (ht.containsKey(s.charAt(i)) && hs.get(s.charAt(i)) <= ht.get(s.charAt(i))) cnt++;

            while (j < i && (!ht.containsKey(s.charAt(j)) || hs.get(s.charAt(j)) > ht.get(s.charAt(j)))) {
                int count = hs.get(s.charAt(j)) - 1;
                hs.put(s.charAt(j), count);
                j++;
            }
            if (cnt == t.length() && i - j + 1 < len) {
                len = i - j + 1;
                ans = s.substring(j, i + 1);
            }
        }
        return ans;
    }

你可能感兴趣的:(Leetcode,java,数据结构,leetcode)