【数组&双指针】LeetCode 76. 最小覆盖子串【困难】
作者:互联网
给你一个字符串 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() window = dict() # 用need记录所有目标字符的个数 for _char in t: if _char not in need: need[_char] = 0 window[_char] = 0 need[_char] += 1 # 用双指针遍历源字符串 left, right = 0, 0 # 有效长度:记录窗口中目标字符的每一类字符是否个数已经满足,满足就加1 valid = 0 # 记录窗口的右侧位置 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]
标签:子串,字符,right,窗口,个数,char,76,need,LeetCode 来源: https://www.cnblogs.com/ariel-dreamland/p/16200412.html