题目链接
https://leetcode.com/problems/find-all-anagrams-in-a-string/
题目描述
给定一个字符串 s 和一个非空字符串 p,找到 s 中所有是 p 的字母异位词的子串,返回这些子串的起始索引。字母异位词指字母相同,但排列不同的字符串。字符串只包含小写英文字母,并且字符串 s 和 p 的长度都不超过 20100。不考虑答案输出的顺序。
示例
输入:s:"cbaebabacd" p:"abc"
输出:[0,6]
起始索引等于 0 的子串是 "cba", 它是 "abc" 的字母异位词。
起始索引等于 6 的子串是 "bac", 它是 "abc" 的字母异位词。
输入:s:"abab" p:"ab"
输出:[0,1,2]
起始索引等于 0 的子串是 "ab", 它是 "ab" 的字母异位词。
起始索引等于 1 的子串是 "ba", 它是 "ab" 的字母异位词。起始索引等于 2 的子串是 "ab", 它是 "ab" 的字母异位词。
解题思路
此题就是在s中找出是p的排列的子串,可看作【leetcode-Python】-滑动窗口-567. Permutation in String的扩展。初始化列表res存储返回结果,在此题中,在s中找到一个p的排列时,不是直接返回True,而是子串的起始索引加入res。循环结束后返回res。(从示例中可以看出,子串和p相同也算是字母异位词)
Python实现
class Solution:
def findAnagrams(self, s: str, p: str) -> List[int]:
from collections import defaultdict
result = [] #存储符合条件的子串起始索引
window = defaultdict(int)
target = defaultdict(int)
for i in p: #计数p中各个字符出现的个数
target[i] += 1
left,right = 0,0
valid = 0
while(right<len(s)):
#预备加入窗口的字符
c = s[right]
right += 1
#更新数据
if(c in target):
window[c] += 1
if(window[c] == target[c]):
valid += 1
while(right-left == len(p)):
#判断是否是p的一个排列
if(valid == len(target)):
result.append(left)
#左边界右移
d = s[left]
left += 1
#更新数据
if(d in target):
if(window[d]==target[d]):
valid -= 1
window[d] -= 1
return result