接着上一篇 双指针滑动窗口整理——长度最小的子数组、水果成篮 继续整理。
题目:76. 最小覆盖子串
此题对于滑动窗口的思路其实与之前差不多,难点在于缩放窗口的条件。
题意解读:
要点一
- 题目中说“*对于 t 中重复字符,我们寻找的子字符串中该字符数量必须不少于
t
中该字符数量。”说明我们需要对t
中字母及其个数进行记录,这里我们用字典requiredsub
来表示。这也是我们求解的子串所需要包含的单词及其数量。 - 在遍历过程中,每次获得一个属于
t
的单词,就将requiredsub[s[j]] -= 1
。 - 当该字典中所有的字母的值为非正数的时候就是滑动窗口要缩放的时候。
要点二
那如何判断requiredsub
中所有元素的值是负数呢?
我们设置了requiredlen
,初始化为t
的长度。当所求子串还需要更多包含t
中元素的时候,(requiredsub[s[j]] > 0
)的时候,requiredlen -= 1
。
-
requiredsub[k]
是正数表示子串中还需要几个k
元素。0
则为不需要,负数则是过剩。 -
我们举个例子来理解一下,比如
s = 'aab' t = 'ab'
,当i = 0, j = 1
时requiredsub['a'] = 0
,表示子串其实不再需要更多a
,所以这时候requiredlen
并不需要变化。
要点三
在i
需要需要变化的时候(向后移动),对于requiredsub
和requiredlen
有一个与要点二相反的变化。即先判断子串中包含t
中的元素是否过剩(如果没有过剩,那么 requiredsub[s[i]] == 0
)则requiredlen += 1
。
from collections import Counter
class Solution(object):
def minWindow(self, s, t):
minstring = ''
minlen = len(s) + 1
requiredsub = Counter(t) #记录需要单词的所需数目
i = 0
requiredlen = len(t)
for j in range(len(s)):
if s[j] in t:
if requiredsub[s[j]] > 0: requiredlen -= 1
requiredsub[s[j]] -= 1
while requiredlen == 0:
curlen = j - i + 1
if minlen > curlen:
minlen = curlen
minstring = s[i:j+1]
if s[i] in t:
if requiredsub[s[i]] == 0: requiredlen += 1
requiredsub[s[i]] += 1
i += 1
return minstring