567 字符串的排列(双指针、哈希表)

43 篇文章 0 订阅

1. 问题描述:

给定两个字符串 s1 和 s2,写一个函数来判断 s2 是否包含 s1 的排列。换句话说,第一个字符串的排列之一是第二个字符串的子串 。

示例 1:

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

示例 2:

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

提示:
1 <= s1.length, s2.length <= 10 ^ 4
s1 和 s2 仅包含小写字母
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/permutation-in-string

2. 思路分析:

这道题目属于经典的双指针(滑动窗口)题目,与力扣438题本质上是一样的,438题求解的是满足条件的所有排列,这道题目求解的是否存在这样的排列,经典的做法是使用一个哈希表或者两个哈希表和结合双指针来维护长度为k的窗口,力扣的438题使用一个哈希表来维护窗口,这里使用两个哈希表S1,S2来维护长度为k窗口,其中k为字符串s1的长度,我们可以先将s1中字符出现的次数存储到S1中,在遍历字符串的时候维护长度为k的窗口(当发现当前的窗口的长度大于k之后那么需要删除掉左边窗口的字符),如何判断当前两个哈希表中对应字符出现的次数完全相同呢?我们可以声明一个变量count来维护哈希表S1中匹配的字符数量,但是如何在遍历字符的时候来更新这个变量呢?可以发现我们在维护长度为k的窗口的时候只会修改哈希表S2中对应窗口的左右边界的值,所以我们可以通过判断在添加和删除当前字符前后在两个哈希表中的关系来更新count,也即添加字符和删除字符的时候是从相等状态转为不相等状态还是从不相等状态状态转为相等状态来更新count,最后判断count是否等于了哈希表中匹配的字符数量,如果相等说明存在这样的排列返回True即可。

3. 代码如下:

使用两个哈希表进行维护:

class Solution:
    # 判断当前的字符在S1和S2中是否相等
    def check(self, c: str, S1: dict, S2: dict):
        if c in S1 and c in S2 and S1[c] == S2[c]:
            return True
        return False

    # 这里使用两个哈希表来维护
    def checkInclusion(self, s1: str, s2: str) -> bool:
        S1, S2 = dict(), dict()
        # 将s1中字符出现的次数存储到哈希表S1中
        for c in s1:
            if c not in S1:
                S1[c] = 1
            else:
                S1[c] += 1
        i, j = 0, 0
        count = 0
        while i < len(s2):
            c = s2[i]
            # 添加当前的s2[i]之前两个字符数量是相等的说明需要添加之后就不相等了所以需要减1
            if self.check(c, S1, S2): count -= 1
            # 更新S2中字符出现的次数
            if c not in S2:
                S2[c] = 1
            else:
                S2[c] += 1
            # 添加了当前字符之后发现相等了说明匹配的字符数量加1, 并且这上面和当前这个check函数的if判断只会进入其中一个或者都不进入, 对于窗口的左边界也是类似这样判断
            if self.check(c, S1, S2): count += 1
            c = s2[j]
            if i - j + 1 > len(s1):
                if self.check(c, S1, S2): count -= 1
                S2[c] -= 1
                if self.check(s2[j], S1, S2): count += 1
                j += 1
            # 匹配了S1中的所有字符
            if count == len(S1): return True
            i += 1
        return False

修改一下438题的代码(使用一个哈希表进行维护):

from typing import List
 
class Solution:
    def checkInclusion(self, s1: str, s2: str) -> List[int]:
        dic = dict()
        for c in s1:
            if c in dic:
                dic[c] += 1
            else:
                dic[c] = 1
        n = len(s2)
        i, j = 0, 0
        staisfy = 0
        res = list()
        # 其实每一次维护的是长度为k的窗口, k = len(p)
        while i < n:
            c = s2[i]
            # 当前需要匹配的字母c的次数减1
            if c in dic: dic[c] -= 1
            # 当前这个字母的次数满足要求
            if c in dic and dic[c] == 0:
                staisfy += 1
            while i - j + 1 > len(s1):
                # 删除最左边的字符如果删除的字符刚好是满足种类的数目那么satisfy需要减1
                if s2[j] in dic and dic[s2[j]] == 0: staisfy -= 1
                if s2[j] in dic:
                    dic[s2[j]] += 1
                j += 1
            if staisfy == len(dic): return True
            i += 1
        return False
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值