
直觉:
滑动窗口 + 排序法
窗口的大小会始终保持为 p 的长度,保证每次比较的都是相同长度的子串
窗口右移
排序比较
python
class Solution:
def findAnagrams(self, s: str, p: str) -> List[int]:
if len(s) < len(p):
return []
if not s or not p:
return []
res = []
p_sorted = sorted(p) # 排序 p 以便与窗口进行比较
# 使用切片获取初始窗口
for i in range(len(p) - 1, len(s)):
window = s[i - len(p) + 1: i + 1] # 正确获取窗口
if sorted(window) == p_sorted:
res.append(i - len(p) + 1) # 存储当前窗口的起始索引
return res
排序的时间复杂度是 O(k log k),其中 k 是 p 的长度。
每次滑动窗口时需要对窗口进行排序
时间复杂度 :O(n * k log k),其中 n 是字符串 s 的长度,k 是字符串 p 的长度
空间复杂度 :O(n + k),其中 n 是字符串 s 的长度,k 是字符串 p 的长度。
如果字符串 p 较大(即 k 较大),排序操作的代价会比较高
滑动窗口 + 频率计数法
python
class Solution:
def findAnagrams(self, s: str, p: str) -> List[int]:
cnt_p = Counter(p) # 统计 p 中每个字符的频率 "abc" -> Counter({'a': 1, 'b': 1, 'c': 1})
cnt_window = Counter() # 统计 s 中当前窗口的字符频率
plen = len(p)
res = []
left = 0
for right in range(len(s)):
cnt_window[s[right]] += 1 # 右端点字符进入窗口,增加该字符的计数
winlen = right - left +1
if winlen < plen:
continue # 继续for循环移动右指针
# 达到p长度
else:
if cnt_p == cnt_window: # # 如果窗口的字符频率和 p 的字符频率一样,说明是异位词
res.append(left) # 记录左端点的索引
cnt_window[s[left]] -= 1 # 左端点移出windows
left += 1 # 左指针前进
else :
cnt_window[s[left]] -= 1 # 左端点移出windows
left += 1 # 左指针前进
return res
总时间复杂度 :O(n×k)
其中 n 是字符串 s 的长度,k 是字符串 p 的长度。
空间复杂度: O(k+n)