题目描述
给定两个字符串 s 和 p,找到 s 中所有 p 的 异位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。
异位词 指由相同字母重排列形成的字符串(包括相同的字符串)。
示例 1:
输入: s = "cbaebabacd", p = "abc"
输出: [0,6]
解释:
起始索引等于 0 的子串是 "cba", 它是 "abc" 的异位词。
起始索引等于 6 的子串是 "bac", 它是 "abc" 的异位词。
示例 2:
输入: s = "abab", p = "ab"
输出: [0,1,2]
解释:
起始索引等于 0 的子串是 "ab", 它是 "ab" 的异位词。
起始索引等于 1 的子串是 "ba", 它是 "ab" 的异位词。
起始索引等于 2 的子串是 "ab", 它是 "ab" 的异位词。
提示:
1 <= s.length, p.length <= 3 * 104- s 和 p 仅包含小写字母
滑动窗口
使用数据结构 dict 构造一个滑动窗口,名为 window。window 中存储窗口中字符出现的次数。
若窗口内字符为 abb,window 结构如下:
window = {
'a': 1,
'b': 2
}
- 将 p 中字符初始化为一个待匹配窗口 need,同样是 dict 结构,记录 p 中每个字符出现的频率。
- 初始化一个变量 valid,记录 window 与 need 中有多少个字符出现频率相同
from collections import defaultdict
need = defaultdict(int)
for i in p:
need[i] += i
- 从s 的等一个字符开始,逐渐加入窗口,直到窗口长度为待匹配字符串 p 的长度。
- 并判断新进入窗口的字符是否在待匹配字符中,即是否在need中。
- 如果在 need 中,判断 window 中此字符出现频率是否等于对应在 need 中出现的频率,如果相等,将valid + 1
- 如果
valid == len(need), 即表示滑动窗口中字符与字符出现频率与陪匹配窗口 need 一致,将 left 加入结果列表
left, right = 0, 0 # 窗口左右指针,初始状态窗口长度为 0,窗口内没值
res = [] # 结果列表
while left < right:
right += 1 # 增加窗口长度,使窗口增加一个值
c = s[left] # 窗口内增加的值
# 判断
if c in need:
window += 1
if window[c] == need[c]:
valid += 1
-
当滑动窗口长度等于待匹配窗口p的长度时,收缩窗口
- 收缩窗口时,判断窗口内字符是否满足待匹配子串
- 收缩窗口时,窗口内字符计数对应减少
- 若左侧弹出窗口的字符,在 window 中出现的频率与在 need 中出现的频率相同,
valid - 1
-
滑动窗口长度小于待匹配窗口时,右指针右移增大窗口
if right - left == len(p):
if valid == len(need):
res.append(left)
d = s[left]
if d in window:
if window[d] == need[d]:
valid -= 1
window[d] -= 1
left += 1
完整代码
class Solution:
def findAnagrams(self, s: str, p: str) -> List[int]:
from collections import defaultdict
window, need = defaultdict(int), defaultdict(int)
# 初始化 need, 子串中相同字符 +1
for i in p:
need[i] += 1
left, right = 0, 0 # 左闭右开窗口
valid = 0 # 记录窗口中字符数满足对应子串字符数的个数
res = []
# 创建窗口
while right < len(s):
c = s[right]
right += 1
if c in need:
window[c] += 1
# 窗口内此字符数量是否达到要求
if window[c] == need[c]:
valid += 1
# 当窗口长度大于子串长度时,收缩窗口, 同时判断窗口内元素是否满足子串要求
while (right - left) == len(p):
if valid == len(need):
res.append(left)
# 窗口内数据更新
d = s[left]
if d in window:
if window[d] == need[d]:
valid -= 1
window[d] -= 1
left += 1
return res