这个题解使用了滑动窗口的思路。首先用 Counter 统计 s1 中每个字符出现的次数,作为需要满足的条件。然后在 s2 上滑动窗口,扩张和收缩窗口,并统计窗口内每个字符的出现次数。当窗口内某个字符的出现次数与 s1 中对应的次数相等时,说明找到了一个符合条件的字符。当所有字符都符合条件,且窗口大小等于 s1 的长度时,说明找到了一个 s1 的排列,返回 True。如果滑动到 s2 的末尾还没找到,则返回 False。
时间复杂度: O(n)
空间复杂度: O(1)
from collections import Counter
class Solution:
def checkInclusion(self, s1: str, s2: str) -> bool:
# 存储滑动窗口内每个字符出现的次数
window = {}
# 存储 s1 中每个字符出现的次数
need = Counter(s1)
# 记录滑动窗口内满足条件的字符个数
valid = 0
# 滑动窗口的左右指针
left,right = 0,0
while right < len(s2):
# 将 s2[right] 加入窗口
c = s2[right]
right += 1
# 如果 s2[right] 不在 s1 中,重置窗口
if c not in need:
left = right
window = {}
valid = 0
else:
# 更新窗口内字符出现的次数
window[c] = window.get(c,0) + 1
# 如果窗口内字符 c 的出现次数与 s1 中对应的次数相等,valid 加 1
if window[c] == need[c]:
valid += 1
# 如果窗口内所有字符都满足条件,判断窗口大小是否等于 s1 的长度
while valid >= len(need):
if right-left == len(s1):
return True
# 将 s2[left] 移出窗口
d = s2[left]
left += 1
# 更新窗口内字符出现的次数
window[d] -= 1
# 如果窗口内字符 d 的出现次数小于 s1 中对应的次数,valid 减 1
if window[d] < need[d]:
valid -= 1
return False