zl程序教程

您现在的位置是:首页 >  其他

当前栏目

【数组&双指针】LeetCode 76. 最小覆盖子串【困难】

ampLeetCode数组 指针 最小 覆盖 子串 困难
2023-09-14 08:59:35 时间

给你一个字符串 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) 时间内解决此问题的算法吗?

【分析】

双指针方案。

首先:

(1)用valid表示目标字符窗中每一类字符的个数是否都满足条件;

(2)用hash表need记录目标串中每一个字符的个数;

(3)用hash表window记录当前窗口中,包含的目标字符的个数;

(4)用length记录当前window窗口的长度。

思路:

遍历源字符串,利用双指针,记录窗口的位置,当窗口中每个目标字符的个数与目标字符串中对应字符的个数都相等时,就停止移动右侧指针,开始缩小左侧指针。

缩小左侧指针时,不断更新窗口长度,并更新窗口中每个目标字符的个数,当窗口中目标字符的个数与目标字符串中的对应字符的个数相等时,就减小有效长度,缩小窗口。

注意:

这里,为了避免边界条件的讨论,我们将双指针的查找区间设置为[left, right),即左闭右开的查找区间。

那么,初始化查找区间就是[0, 0],最后一个查找区间就是[left, n)。

这种情况下初始查找区间[0, 0),窗口长度为0,只要右侧指针移动一步,窗口中就包含一个元素,同时,窗口的长度就是length = right - left,比较方便。

class Solution:
    def minWindow(self, s: str, t: str) -> str:
        need = dict() # 用hash表need记录目标串中每一个字符的个数
        window = dict() # 用hash表window记录当前窗口中,包含的目标字符的个数
        # 用need记录所有目标字符的个数; 开始遍历目标字符串
        for _char in t:
            if _char not in need:
                # 若目标字符串中的字符不在need中,那么need与window均将该字符数目记录为0
                need[_char] = 0 
                window[_char] = 0
            need[_char] += 1 # 跳出if条件语句,需要将遍历到的char在need中进行+1记录
        left, right = 0, 0 # 用双指针遍历源字符串
        valid = 0 # 记录窗口中目标字符的每一类字符是否个数已经满足,满足就加1
        start = 0 # 记录窗口的右侧位置
        length = len(s) + 1 # 将窗口长度初始化为一个无效值,即大于源字符串的长度值
        # 右指针遍历字符串的每一个位置:作为窗口右侧结束位置
        while right < len(s):
            right_char = s[right]
            right += 1 # 增大窗口
            if right_char in need:
                # 若窗口内的最后一个字符在目标字符串中, 更新窗口中的字符个数
                window[right_char] += 1
                if need[right_char] == window[right_char]:
                    # 当前字符在窗口中的字符个数与目标字符串的字符个数相等,更新有效长度
                    valid += 1
            # 当窗口中的每一类字符个数都与目标串中的每一类字符个数相等,就不断缩小左侧指针
            while valid == len(need):
                # 更新最小的窗口长度
                if right - left < length:
                    start = left
                    length = right - left
                first_char = s[left]
                left += 1 # 缩小窗口

                # 若左侧字符在目标字符里面
                if first_char in need:
                    # 当前字符在窗口中的个数,与目标串个数相等,就减少有效长度
                    if window[first_char] == need[first_char]:
                        valid -= 1
                    # 更新窗口中的字符个数
                    window[first_char] -= 1
        return "" if length == len(s) + 1 else s[start:start + length]