E-438. Find All Anagrams in a String
这是个滑动窗口的问题:
滑动窗口题模板↑
一种方法的视频讲解:
#0 暴力, TLE, 略
# 2 Sliding window method 1
'''
这个方法就是视频里的方法, 我觉得是这题最好的解法
https://leetcode.com/problems/find-all-anagrams-in-a-string/discuss/92059/O(n)-Sliding-Window-JAVA-Solution-Extremely-Detailed-Explanation
'''
class Solution:
def findAnagrams(self, s: str, p: str) -> List[int]:
dict_s = dict(zip(range(0, 26), [0]*26))
dict_p = dict(zip(range(0, 26), [0]*26))
for char in p:
dict_p[ord(char)-ord('a')] += 1
res = []
step = len(p)
for i in range(0, len(s)):
if i >= step:
dict_s[ord(s[i-step])-ord('a')] -= 1
dict_s[ord(s[i])-ord('a')] += 1
if dict_s == dict_p:
res.append(i + 1 - step)
return res
# 2 自己写的:
class Solution:
def findAnagrams(self, s: str, p: str) -> List[int]:
dict_s = dict(zip(range(0,26),[0]*26))
dict_p = dict(zip(range(0,26),[0]*26))
step = len(p)
res = []
for char in p:
dict_p[ord(char)-ord('a')] += 1
for char in s[0:step]:
dict_s[ord(char)-ord('a')] += 1
if dict_s == dict_p:
res.append(0)
for i in range(step, len(s)):
dict_s[ord(s[i])-ord('a')] += 1
dict_s[ord(s[i-step])-ord('a')] -= 1
if dict_s == dict_p:
res.append(i + 1 - step)
return res
# 3 Sliding window method 2
'''
我的解释:
begin是窗口左边界, end是窗口右边界, counter是map里value非0的item的数量(此题counter最多是
26个(即26个字母作为key, 最多有26个item)), map代表此时缺少的字符以及相应的数量
(如果是负数, 就是当前多余的字符)
思路就是end不断右移, 消耗map里的字符(遇到end上的字符, 就从map中减1), 直到map里的
字符value都小于等于0; 再把begin右移, 补充map里的字符(遇到begin上的字符, 就从map
中加1), 直到map里有一个字符的 value = 1 (下面写的是>0, 但是和=1等价, 因为counter等于0时
才循环)时, 此时, 我们可以知道, 在s中, begin和end中间的部分(即,s[begin:end], 左闭右开)
消耗了p所有的char, 至于是否恰好消耗, 我们用end-begin == len(p)进行判断=>如果相等, 则说明
s[begin:end]恰好消耗了p, which means s[begin:end]和p互为Anagram.
例子:
s = a a c c a e a b c b a a
p = a b a c
map = {a:2, b:1 c:1},
begin, end = 0
'''
class Solution:
def findAnagrams(self, s: str, p: str) -> List[int]:
res = []
if len(p) > len(s):
return res
map = {}
for char in p:
map[char] = map.get(char, 0) + 1
counter = len(map)
begin, end = 0, 0
head = 0
while end < len(s):
c = s[end]
if c in map:
map[c] -= 1
if map[c] == 0:
counter -= 1
end += 1
while counter == 0:
tempc = s[begin]
if tempc in map:
map[tempc] += 1
if map[tempc] > 0:
counter += 1
if end-begin == len(p):
res.append(begin)
begin += 1
return res
# 3 另一个方法
'''
https://www.programiz.com/python-programming/methods/built-in/hash
hash函数返回唯一hash value, 所以如果是anagram, 那么两个string中每一个char的hash
值应该相等, 所以这也是一种滑动窗口的方法, 而且更快. 但是可能存在隐患就是, 如果把里面的
hash替换成ord, 就能知道, 可能会存在ord值恰好相等的情况, 比如test case为"af"和"be"
的时候, 那么hash值会不会也出现这种情况呢? 虽然大概率不会, 但是不是百分之百.
'''
class Solution:
def findAnagrams(self, s: str, p: str) -> List[int]:
res = []
if len(p) >len(s):
return res
hash_p =hash_s = 0
for i in range(len(p)):
hash_p += hash(p[i])
hash_s += hash(s[i])
if hash_p==hash_s:
res.append(0)
for i in range(len(p), len(s)):
hash_s += hash(s[i]) - hash(s[i-len(p)])
if hash_p == hash_s:
res.append(i- len(p)+1)
return res
Last updated
Was this helpful?