LeetCode: 76. 最小覆盖子串

84 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第3天,点击查看活动详情

76. 最小覆盖子串

来源:力扣(LeetCode)

链接: leetcode.cn/problems/mi…

给你一个字符串 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 <= 10510^5
  • s 和 t 由英文字母组成

解法

  • 双指针方法:要求连续的字符串,看是否包含目标字符串。可以通过判断滑动窗口中的元素和出现次数是否与目标字符串相同。如果相同则从中找最小的那个滑动窗口。使用双指针,右指针往前,如果满足条件,左指针也往右去移动,去除掉一些不需要的元素,这里次数判断可以通过哈希表来快速的查找。 要求返回字符串 s中包含字符串 t 的全部字符的最小窗口,利用滑动窗口的思想解决这个问题。因此需要两个哈希表,hs哈希表维护的是s字符串中滑动窗口中各个字符出现多少次,ht哈希表维护的是t字符串各个字符出现多少次。如果hs哈希表中包含ht哈希表中的所有字符,并且对应的个数都不小于ht哈希表中各个字符的个数,那么说明当前的窗口是可行的,可行中的长度最短的滑动窗口就是答案。

代码实现

双指针滑动窗口

python实现

class Solution:
    def minWindow(self, s: str, t: str) -> str:
        if len(s) < len(t):
            return ""
        
        hs = dict()
        ht = dict()
        for char in t:
            ht[char] = ht.get(char, 0) + 1
        
        left = 0
        right = 0
        cnt = 0
        res = ""
        while right < len(s):
            hs[s[right]] = hs.get(s[right], 0) + 1

            if s[right] in ht and hs[s[right]] <= ht[s[right]]:
                cnt += 1
            
            # left move right
            while left <= right and (s[left] not in ht or hs[s[left]] > ht[s[left]]):
                hs[s[left]] -= 1
                left += 1
            
            # 判断长度
            if cnt == len(t):
                if not res or right-left+1 < len(res):
                    res = s[left: right+1]
            right += 1
        return res

c++实现

class Solution {
public:
    string minWindow(string s, string t) {
        if (s.size() < t.size()) return "";
        map<char, int> hs;
        map<char, int> ht;
        for(char ch: t) {
            if (ht.find(ch) != ht.end())
                ht[ch] += 1;
            else
                ht[ch] = 1;
        }

        int left = 0, right = 0, cnt = 0;
        string res = "";
        while (right < s.size()) {
            if (hs.find(s[right]) != hs.end()) hs[s[right]] += 1;
            else hs[s[right]] = 1;
            if (ht.count(s[right]) != 0 && hs[s[right]] <= ht[s[right]]) cnt++;

            while(left <= right && (ht.find(s[left]) == ht.end() or hs[s[left]] > ht[s[left]])) {
                hs[s[left]]--;
                left++;
            }
            if (cnt == t.size()) {
                if (res.empty() || right-left+1 < res.size())
                    res = s.substr(left, right-left+1);
            }
            right++;
        }
        return res;
    }
};

复杂度分析

  • 时间复杂度: O(n)O(n)
  • 空间复杂度: O(n)O(n)

参考