给定一个字符串 S、一个字符串 T,请在字符串 S 里面找出:包含 T 所有字母的最小子串。
示例:
输入: S = "ADOBECODEBANC", T = "ABC"
输出: "BANC"
说明:
提示:根据LeetCode的官方解答,字符串T中可能有重复的字符,所以我们的答案需要保证字符类型和数量都一致。例如:T=“aabc”,则最小字串可能为“baac”,而不是“bac”
所以可以从字符串T中字母的出现的类型和频率入手,两者都要统计。可以通过python的字典类型来记录。
滑动窗口算法可以用以解决数组/字符串的子元素问题,它可以将嵌套的循环问题,转换为单循环问题,降低时间复杂度。
窗口可以是固定大小,起始和终止位置同时变化。
也可以是可变大小,起始和终止位置不同时变化。
def minWindow(s: str, t: str) -> str:
left = 0
minlen = len(s)+1
i = 1 # 指针
result = ""
char_t = dict() # 字典,用于统计t中不同字符出现的个数
char_win = dict() # 字典,用于统计滑动窗口中不同字符的个数
count = 0 # 用于统计滑动窗口中有多少字符满足数量需求
FORM = 0 # 记录t中不同字符的格个数,count与form相等时满足条件
if not s or not t: # 空串
return result
for i in t:
#遇到新的字符则加入
if not (i in char_t):
char_t[i]=1
char_win[i]=0
FORM+=1
else:
char_t[i]+=1
for i in range(len(s)):
letter=s[i]
if letter in char_t:
char_win[letter]+=1
if char_win[letter]==char_t[letter]:
count+=1
if count==FORM:#找到满足条件的字串
# 收缩左边框
if i!=len(s):#滑动窗口未扩张到最后一个字符
while(True):
#字符不在t中出现
if(s[left] not in t):
left += 1
#字符在t中出现
else:
temp_len=len(s[left:i+1])
if (char_win[s[left]]>char_t[s[left]])and(temp_len>len(t)):
char_win[s[left]]-=1
left+=1
else:
break
#更新minlen和result
temp=s[left:i+1]
if len(temp)<minlen:
minlen=len(temp)
result=temp
else:
while(True):
#字符不在t中出现
if(s[left] not in t):
left += 1
#字符在t中出现
else:
temp_len=len(s[left:])
if (char_win[s[left]]>char_t[s[left]])and(temp_len>len(t)):
char_win[s[left]]-=1
left+=1
else:
break
#更新minlen和result
temp=s[left:]
if len(temp)<minlen:
minlen=len(temp)
result=temp
char_win[s[left]]-=1
count-=1
left+=1
return result
S = "ADOBECODEBANC"
T = "ABC"
print("答案:"+minWindow(S, T))
S2 = "abbbbbbbbabc"
T2 = "abc"
print("答案2:"+minWindow(S2, T2))
这个题的困难之处在于如何判断字串满足条件。一开始注意力都集中在字符的类型相同上,数量只是附带检验。但实际上可以巧妙利用字符出现的频率(数量)来作为判断条件。
其次滑动窗口扩张到最后一个字符的时候要单独判断,因为python的字符串切片[begin:end]
截取的字符串下标是从begin到end-1,如果i移动到字符串末尾,i+1会越界
原文:https://www.cnblogs.com/zhoujiayingvana/p/12310145.html