- LeetCode 热题 100 - 两数之和
- 字母异位词分组
- 最长连续序列
- 移动零
- 盛最多水的容器
- 三数之和
- 接雨水
- 找到字符串中所有字母异位词
- 无重复字符的最长子串
- 和为 K 的子数组
- 滑动窗口最大值
找到字符串中所有字母异位词
class 哈希表,字符串,滑动窗口给定两个字符串 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
的长度。我们使用两个计数器来存储字符频次。
这种方法利用滑动窗口和字符计数器,能够高效地找到所有异位词子串的起始索引