算法438. 找到字符串中所有字母异位词
给定两个字符串
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" 的异位词。
解法一:
# 解题思路:hash表、双指针、滑动窗口
class Solution:def findAnagrams(self, s: str, p: str) -> List[int]:# 首先判断特殊情况if len(p) > len(s):return []ans=[]# 字符串字典化,方便后续对比cnt_p = defaultdict(int)for a in p:cnt_p[a]+=1p_len=len(p)# 初始化一个长度为p的窗口字典cnt_window = defaultdict(int)for b in range(p_len):cnt_window[s[b]]+=1# 如果和初始化窗口字典相同,那么其实位置就是0if cnt_p==cnt_window:ans.append(0)s_len=len(s)# 为什么从p_len开始?为什么left=right-p_len,这样[left,right]的窗口长度不就大于len(p)了吗?# 回答上面的问题,因为在对比cnt_window和cnt_p前,先执行了cnt_window[s[left]]-=1,实际起始位置是left+1for right in range(p_len,s_len):left = right-p_lencnt_window[s[right]]+=1cnt_window[s[left]]-=1# 这个是为了防止在对比时,出现value=0的情况,影响对比if cnt_window[s[left]]==0:del cnt_window[s[left]]if cnt_window==cnt_p:ans.append(left+1)return ans
解法二:
class Solution:def findAnagrams(self, s: str, p: str) -> List[int]:ans=[]# 创建一个字符计数的字典cnt_p = Counter(p)cnt_window = Counter()for right,c in enumerate(s):left=right-len(p)+1cnt_window[c]+=1if left<0:continueif cnt_window==cnt_p:ans.append(left)cnt_window[s[left]]-=1return ans