2021-02-10 Leetcode每日刷题
题目
给定两个字符串 s1 和 s2,写一个函数来判断 s2 是否包含 s1 的排列。
换句话说,第一个字符串的排列之一是第二个字符串的子串。
示例1:
输入: s1 = “ab” s2 = “eidbaooo”
输出: True
解释: s2 包含 s1 的排列之一 (“ba”).
示例2:
输入: s1= “ab” s2 = “eidboaoo”
输出: False
我的思路
首先根据之前几天的题目知道这是一个滑动窗口题。我的想法是套用昨天的基本滑动窗口模板,用字典记录下窗口[left,right]内部每个字母出现的次数。当该字典与s1的字典相等时表示当前窗口内部是一个s1的排列。
另外需要考虑的情况包括当right指向的数不在s1内部时可以令left和right都指向下一个数,当窗口长度等于s1长度的时候是定长的滑动窗口,因此美移动一格right需要移动一格left,在移动left之前要把其指向的数字出现的次数-1,窗口长度-1。
class Solution:
def checkInclusion(self, s1: str, s2: str) -> bool:
left = 0
right = 0
counter1 = collections.Counter()
counter2 = collections.Counter()
nums = 1
for i in s1:
counter1[i]+=1
while right<len(s2):
if s2[right] not in s1:
right+=1
left = right
counter2 = collections.Counter()
nums = 1
continue
counter2[s2[right]]+=1
if counter1==counter2:
return True
if nums==len(s1):
counter2[s2[left]]-=1
if counter2[s2[left]] == 0:
counter2.pop(s2[left])
left+=1
nums-=1
right+=1
nums+=1
return False
提交结果:
参考思路:
其实和这个思路差不多,但是从简化代码的角度来看不必要分这么多情况,直接用一个定长为len(s1)的滑动窗口放在s2中,right+1的同时left+1,判断内部的counter2是否等于counter1。
class Solution(object):
def checkInclusion(self, s1, s2):
"""
:type s1: str
:type s2: str
:rtype: bool
"""
# 统计 s1 中每个字符出现的次数
counter1 = collections.Counter(s1)
N = len(s2)
# 定义滑动窗口的范围是 [left, right],闭区间,长度与s1相等
left = 0
right = len(s1) - 1
# 统计窗口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
作者:fuxuemingzhu
链接:https://leetcode-cn.com/problems/permutation-in-string/solution/zhu-shi-chao-xiang-xi-de-hua-dong-chuang-rc7d/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
官方提供的两个思路也都很好,但是我记不住。有空补上。写作业去了。