做了leetcode窗口滑动的部分题目
3. 无重复字符的最长子串
76. 最小覆盖子串
209. 长度最小的子数组
438. 找到字符串中所有字母异位词
567. 字符串的排列
1004. 最大连续1的个数 III
有关子串、子数组问题都可以考虑滑动窗口
我自己写的窗口滑动的题的大致模板是这样的:
for i ,c in enumerate(s):
if 不满足条件:
进行下一个循环
看是否需要更新什么值
else:
收缩窗口(增加左边界)
更新结果
所以需要做的2件事情为:
- 怎样判断是否满足条件
- 什么时候停止收缩左边界
需要的变量为:
- res: 记录结果
- l: 记录左边界
- 辅助判断是否满足条件的变量,很可能是集合、字典或者栈
下面以这个模板依次讲解每个题
3. 无重复字符的最长子串
分析:
for i ,c in enumerate(s):
if 不满足条件:
进行下一个循环
看是否需要更新什么值
else:
收缩窗口(增加左边界)
更新结果
结果是不包含重复字符的子串,就用集合记录窗口中的字符
判断条件:
for i ,c in enumerate(s):
if c不在集合中:
将c加入到集合中
else:
更新结果
收缩左边界的值,要想把集合中包括c,左边界必须在上一个c的位置+1,因为有可能 l>c的位置+1
所以。。。
代码如下:
class Solution(object):
def lengthOfLongestSubstring(self, s):
"""
:type s: str
:rtype: int
"""
if not s:
return 0
hashmap={} #key为字符,value为位置
res=0
l=0
for index,c in enumerate(s):
if c not in hashmap:
hashmap[c]=index
else:
l=max(1+hashmap[c],l) #这个地方更新左边的时候,有可能l的值比hashmap[c]+1要大
hashmap[c]=index
res=max(res,index-l+1)
return res
76. 最小覆盖子串
滑动窗口外面的时间复杂度为O(n),所以外层循环里面不能出现循环,但是我用了循环。。。。菜鸡的卑微
用两个哈希表req、count分别记录满足条件的子串每个字符应该出现的个数和每个字符已经出现的个数,
for _ in req:
if 对于每个 _ ,都有count[_] >req[_],满足条件,开始收缩左边界
否则,进行下一个循环
代码:
class Solution(object):
def minWindow(self, s, t):
"""
:type s: str
:type t: str
:rtype: str
"""
res=''
l=0
req=defaultdict(int)
for i in t:
req[i]+=1
count=defaultdict(int)
for r,c in enumerate(s):
count[c]+=1
flag=0 #flag为1时,不满足条件,进行下一个字符,怎样判断不满足条件,
for _ in req:
if req[_]>count[_]:
flag=1
break
if flag:
continue
if not flag: #满足条件,收缩左边界
while count[s[l]]>req[s[l]]:
count[s[l]]-=1
l+=1
if not res:
res=s[l:r+1]
else:
res=res if len(res)<r-l+1 else s[l:r+1]
return res
上面的每个题都是如此,先去吃饭,有时间更新。