LeetCode-567-字符串的排列-滑动窗口

567、字符串的排列

给定两个字符串 s1 和 s2,写一个函数来判断 s2 是否包含 s1 的排列。

换句话说,第一个字符串的排列之一是第二个字符串的子串。

示例1:

输入: s1 = "ab" s2 = "eidbaooo"
输出: True
解释: s2 包含 s1 的排列之一 ("ba").
 

示例2:

输入: s1= "ab" s2 = "eidboaoo"
输出: False

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/permutation-in-string

 
解题思路:
左右设置两个下标,左右下标围成一小块区域为窗口,在要匹配的字符串上进行从前往后的滑动,找到符合题意的子串
窗口初始化:左右下标初始为0
步骤:右下标一个一个往后移动,每当找到一个目标字符,就加入窗口中,直到窗口中包含所有要找的字符,当满足条件时,才移动左下标,来优化结果,缩小窗口,移动时要判断左下标右移后要删掉的那个元素是否是题目所需,如果是还要进行一系列操作,详细参见代码中的注释。
class Solution(object):
    def checkInclusion(self, s1, s2):
        
        windows = dict()
        needs = dict()
        for i in s1:
            if i in needs:
                needs[i] = needs[i] + 1
            else:
                needs[i] = 1
        right = left = 0
        voiad = 0
        while right < len(s2):#右下标不能超过字符串末尾
            c = s2[right]#提取右下标指向的元素c
            right += 1#右下标右移一位
            if c in needs:#如果c是需要的字符,则对字符进行操作,如果不是,直接下次循环,直到右下标指向有用的字符
                if c in windows:#如果c曾找到过,曾放入过窗口中,则直接数量加1
                    windows[c] = windows[c] + 1
                else:#如果c不曾找到过,窗口中还未曾加入过,则置窗口中该字符的数量为1,说明此刻找到了一个
                    windows[c] = 1
                if windows[c] == needs[c]:#如果c这个字符的数量,和要求的c的数量相同,则说明c这个字符找够了,则将已找到的字母数+1
                    voiad += 1
                while voiad == len(needs):#已找到的的字母数=要找的字符集的字母数,说明窗口中已经包含了所有要找的字母了(包括每个字母的不同个数),可以进行窗口的优化了
                    d = s2[left]#记下左下标所指的字符d
                    left = left + 1#左下标右移一位
                    if right - left + 1 == len(s1):#如果窗口长度和要求的s1长度相同,说明不包含冗余字符,符合要求,输出true
                        return True
                    if d in needs:#窗口长度和要求的s1长度不同,要进行滑窗,如果即将剔除的字符d是目标字符之一
                        if windows[d] == needs[d]:#如果窗口中的d字符是找够了的,但剔除后,这个字符就少了一个,就不是数量找够的字符了,那么将已找够的字母数-1
                            voiad -= 1
                        windows[d] = windows[d] - 1#窗口中的d也-1
                   
        return False

 

posted @ 2021-01-19 19:49  _YeLL  阅读(217)  评论(0)    收藏  举报