问题链接:
问题描述:
给定两个字符串 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:
算法思想:
- 把查询数据p进行从大到小排序,
- 对原数组进行遍历,并且规定范围,len(s)-l+1:减少遍历次数,因为后面都不满足p的长度。
- 随后开始遍历,初始坐标为i,选取i到i+l的区间,进行排序,是否相等。
- 相等则输入列表。
#类似于暴力。非常慢
class Solution:
def findAnagrams(self, s: str, p: str) -> List[int]:
l=len(p)
p=sorted(p)
ans=[]
c=[]
for i in range(0,len(s)-l+1):
c=sorted(s[i:i+l])
if c==p:
ans.append(i)
return ans
代码2:
利用不定长滑动窗口的思想。
- 利用Counter计数器对p进行字母的统计。
- 随后遍历数组s,并将遍历的值c放入计数器cnt中,有这个数据则减一。
- 如果发现cnt[c]<0,则可以判断字母c太多,所以需要回复s[left]的cnt中的值,滑动窗口left向前进一。
- 最后一步,判断坐标长度是否满足p的长度,满足,则输入left。
#不定长
class Solution:
def findAnagrams(self, s: str, p: str) -> List[int]:
ans=[]
cnt=Counter(p)
left=0
for right,c in enumerate(s):
cnt[c]-=1
while cnt[c]<0: #字母c太多了
cnt[s[left]]+=1 #左端点字母离开窗口
left+=1
if right-left+1==len(p):
ans.append(left)
return ans
代码3:
定长滑动窗口:
- 右指针每移动一位就增加当前字符计数
- 计算左指针位置,当窗口长度达标时:
- 比较当前窗口与目标p的字符分布,若匹配则将左指针加入结果
- 窗口右移前减少左指针字符计数
- 通过动态维护的字符计数器实现O(n)时间复杂度
#定长
class Solution:
def findAnagrams(self, s: str, p: str) -> List[int]:
ans=[]
cnt_p=Counter(p)
cnt_s=Counter()
for right,c in enumerate(s):
cnt_s[c]+=1
left=right-len(p)+1 #确定left的下标
if left<0:
continue #当要验证的数据没有满足的时候,跳过下面继续运作
if cnt_s==cnt_p: #s和p的每种字母的出现次数都相同
ans.append(left) #s左端点下标加入答案
cnt_s[s[left]]-=1 #左端点字母离开窗口
return ans