给定两个字符串 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 仅包含小写字母
要找到字符串 s
中所有 p
的异位词的子串的起始索引,我们可以利用滑动窗口结合字符计数的方法。这种方法能够有效地在 s
中定位所有 p
的异位词。
方法:滑动窗口 + 字符计数
算法步骤
初始化:
使用两个计数器
p_count
和s_count
来记录字符串p
和当前窗口中字符的频次。初始化结果列表
result
来存储异位词子串的起始索引。填充
p_count
:遍历字符串
p
,将每个字符的出现次数记录在p_count
中。滑动窗口遍历
s
:将当前字符添加到
s_count
中,增加其频次。检查当前窗口的大小是否等于
len(p)
:右移窗口的右指针
right
。比较
s_count
和p_count
,如果相等,说明找到了一个异位词,记录其起始索引left
。移动左指针
left
,并减少对应字符在s_count
中的频次。如果等于:
设置窗口大小为
p
的长度len(p)
。遍历字符串
s
,使用一个长度为len(p)
的滑动窗口:返回结果:
返回结果列表
result
,包含所有异位词子串的起始索引。
算法实现
下面是用 Python 实现的代码:
from collections import Counter def find_anagrams(s, p): # 记录p中的字符频次 p_count = Counter(p) # 记录当前窗口中字符频次 s_count = Counter() result = [] # 窗口的左指针 left = 0 # 遍历字符串s for right in range(len(s)): # 增加当前字符到窗口中 s_count[s[right]] += 1 # 窗口大小大于p时,缩小窗口 if right - left + 1 > len(p): # 移除左指针字符的频次 s_count[s[left]] -= 1 if s_count[s[left]] == 0: del s_count[s[left]] # 左指针右移 left += 1 # 窗口大小等于p时,检查异位词 if right - left + 1 == len(p) and s_count == p_count: result.append(left) return result # 示例 s = "cbaebabacd" p = "abc" result = find_anagrams(s, p) print("异位词子串的起始索引:", result)
示例
输入:
s = "cbaebabacd"
,p = "abc"
输出:
[0, 6]
解释
在这个例子中,"cba"
和 "bac"
是 s
中的两个子串,它们都是 p = "abc"
的异位词。
复杂度分析
时间复杂度:O(n + m),其中 n 是字符串
s
的长度,m 是字符串p
的长度。我们需要遍历s
一次,并对p
构建计数器。空间复杂度:O(m),其中 m 是字符串
p
的长度。我们使用两个计数器来存储字符频次。
这种方法利用滑动窗口和字符计数器,能够高效地找到所有异位词子串的起始索引