76. 最小覆盖子串

93 阅读1分钟

题目描述

给你一个字符串 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 的子串中,
因此没有符合条件的子字符串,返回空字符串。

提示:

  • 1 <= s.length, t.length <= 105
  • s 和 t 由英文字母组成

进阶:你能设计一个在 o(n) 时间内解决此问题的算法吗?

思路

首先,我们不难想到暴力的方法,利用双指针在s中选取一块,判断是否包含t中的所有字符数量。

for (int i = 0; i < s.length(); i++) {
    for (int j = i + 1; j < s.length(); j++)
        if (s[i : j] 包含t中的所有字符)
            更新答案
}

但是该方法的时间复杂度应该是大于O(n2)O(n^2)的。那么如何缩小这个时间复杂度呢?

这时候就要想到滑动窗口,利用滑动窗口去判断,可以省去重复判断的步骤。

首先利用滑动窗口的框架,进行填充。

在本题中,need肯定是t中所有字符的数量,window可以是s[left:right]中涵盖t所有字符的数量,valid是window中t所有字符的总类别数。

当valid==need.size()时,表示window中涵盖t中的所有字符,开始收缩窗口,并判断此时s[left:right]是否是最小的子串。那么就可以写出本题的题解。

class Solution {
    public String minWindow(String s, String t) {
        HashMap<Character, Integer> window = new HashMap<>();
        HashMap<Character, Integer> need = new HashMap<>();
        for (char c : t.toCharArray())
            need.put(c, need.getOrDefault(c, 0) + 1);

        int left = 0, right = 0;
        int vaild = 0;
        // 记录最小字串的开始位置和长度
        int start = 0, len = Integer.MAX_VALUE;

        while (right < s.length()) {
            char c = s.charAt(right);
            right++;
            if (need.getOrDefault(c, 0) != 0) {
                window.put(c, window.getOrDefault(c, 0) + 1);
                if (window.get(c) == need.get(c))
                    vaild++;
            }

            while (vaild == need.size()) {
                if (len > right - left) {
                    start = left;
                    len = right - left;
                }
                char d = s.charAt(left);
                left++;
                if (need.getOrDefault(d, 0) != 0) {
                    if (window.get(d) == need.get(d))
                        vaild--;
                    window.put(d, window.get(d) - 1);
                }
            }
        }
        return len == Integer.MAX_VALUE ? "" : s.substring(start, start + len);
    }
}