代码
class Solution:
### 1227 使用滑动窗口统计所有字母数量是否相同(100 ms,15.6 MB)
def findAnagrams(self, s: str, p: str) -> List[int]:
# 初始化两个字符串均为26位的列表(从a到z顺序排列),每一位的数量表示对应字母的数量
ss, pp = [0] * 26, [0] * 26
# 统计p中每一个字母的数量(使用ord来统计,即ASCII码)
for i in p: pp[ord(i) - ord('a')] += 1
# 统计s中第一个窗口的字母情况,窗口大小即为p的长度
for i in s[: len(p)]: ss[ord(i) - ord('a')] += 1
res = []
# 初始化窗口左边界为0,右边界为len(p) - 1
l, r = 0, len(p) - 1
# 当右边界不越界时,进行循环(注意:r比右边界小一!)
while r < len(s) - 1:
# 若ss与pp中所有字母的数量相同,则是字母异位词,添加此时起始下标l
if ss == pp: res.append(l)
# 判断完当前l之后,去掉当前l所指向的字母,l加一右移(先ss减一,再l加一)
ss[ord(s[l]) - ord('a')] -= 1
l += 1
# 判断完当前l之后,r加一右移(先r加一,再ss加一)
r += 1
ss[ord(s[r]) - ord('a')] += 1
# 注意:需要判断最后一个窗口的字符串是否为字母异位词!
if ss == pp: res.append(l)
return res
839. 相似字符串组
class Solution:
def numSimilarGroups(self, strs: List[str]) -> int:
n = len(strs)
f = list(range(n))
def find(x: int) -> int:
if f[x] == x:
return x
f[x] = find(f[x])
return f[x]
def check(a: str, b: str) -> bool:
num = 0
for ac, bc in zip(a, b):
if ac != bc:
num += 1
if num > 2:
return False
return True
for i in range(n):
for j in range(i + 1, n):
fi, fj = find(i), find(j)
if fi == fj:
continue
if check(strs[i], strs[j]):
f[fi] = fj
ret = sum(1 for i in range(n) if f[i] == i)
return ret
567. 字符串的排列(s2 是否包含 s1 的排列)
class Solution:
# 滑窗
def checkInclusion(self, s1: str, s2: str) -> bool:
n = len(s2)
# 定义滑动窗口的范围是 [left, right],闭区间,长度与s1相等
left = 0
right = len(s1) - 1
# 统计 s1 中每个字符出现的次数
counter1 = collections.Counter(s1)
# 统计窗口s2[left, right - 1]内的元素出现的次数
counter2 = collections.Counter(s2[0: right])
while right < n:
# 把 right 位置的元素放到 counter2 中
counter2[s2[right]] += 1
# 如果滑动窗口内各个元素出现的次数跟 s1 的元素出现次数完全一致,返回 True
if counter1 == counter2:
return True
# 窗口向右移动前,把当前 left 位置的元素出现次数 - 1
counter2[s2[left]] -= 1
# 如果当前 left 位置的元素出现次数为 0, 需要从字典中删除,否则这个出现次数为 0 的元素会影响两 counter 之间的比较
if counter2[s2[left]] == 0:
del counter2[s2[left]]
# 窗口向右移动
left += 1
right += 1
return False