leetcode分类刷题:滑动窗口(四、两个序列+窗口不定长类型)

1、同样是给定两个序列,判断短序列在长序列中最短的覆盖连续子序列,那么此时的滑窗长度就大于等于短序列长度了,变为不定长的了
2、本文总结的题型短序列同样为滑动窗口+哈希表+matchKeys标记(覆盖的键数量),这里的覆盖含义恰好为上篇总结中的刚好匹配+过匹配(滑窗内该元素在待匹配的哈希表中存在且数量相等或更多),看起来上篇总结像是本文总结的题型的特殊情况,因为本文的解法和上篇完全一样,且把题型和模板对应起来理解的更深刻

383. 赎金信

这道题目不是本次的总结题型,放在这里主要是为了给出一下覆盖子串的含义:长序列包含的元素种类和数目相同大于等于短序列

'''
383. 赎金信
题目描述:给你两个字符串:ransomNote 和 magazine ,判断 ransomNote 能不能由 magazine 里面的字符构成。
如果可以,返回 true ;否则返回 false 。
magazine 中的每个字符只能在 ransomNote 中使用一次。
示例 1:
    输入:ransomNote = "aa", magazine = "aab"
    输出:true
题眼:ransomNote 能不能由 magazine 里面的字符构成  <=> 是否是覆盖子串
思路:相当于是”242. 有效的字母异位词“的扩展题型,直接利用哈希表判断即可
'''


class Solution:
    def canConstruct(self, ransomNote: str, magazine: str) -> bool:
        # 情况1、ransomNote长度大于magazine
        if len(ransomNote) > len(magazine):
            return False
        # 情况2、判断ransomNote是否为magazine的子集
        # 将magazine转为哈希表
        hashTable = {}
        for ch in magazine:
            if ch not in hashTable:
                hashTable[ch] = 1
            else:
                hashTable[ch] += 1
        # 遍历ransomNote,判断字符在哈希表中的存在情况
        for ch in ransomNote:
            if ch not in hashTable:
                return False
            else:
                if hashTable[ch] == 0:
                    return False
                hashTable[ch] -= 1
        return True


if __name__ == "__main__":
    obj = Solution()
    while True:
        try:
            in_line = input().strip().split('=')
            ransomNote = in_line[1].split(',')[0].strip()[1: -1]
            magazine = in_line[2].strip()[1: -1]
            print(obj.canConstruct(ransomNote, magazine))
        except EOFError:
            break

76. 最小覆盖子串

这道题目除了“移动left缩小滑窗”条件和“更新结果”的位置及操作 稍微有调整外,其它代码与”438. 找到字符串中所有字母异位词”的模板完全一样,也更加符合

'''
76. 最小覆盖子串
题目描述:给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 "" 。
注意:
对于 t 中重复字符,我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量。
如果 s 中存在这样的子串,我们保证它是唯一的答案。
示例 1:
    输入:s = "ADOBECODEBANC", t = "ABC"
    输出:"BANC"
题眼:选出最短的包含t的子序列
思路:与”438. 找到字符串中所有字母异位词”的模板更加符合,特别是matchKeys标记 刚好匹配或过匹配 就是这里的 覆盖 的含义
'''


class Solution:
    def minWindow(self, s: str, t: str) -> str:
        # 情况1、s长度小于t
        if len(s) < len(t):
            return ""
        # 情况2、滑动窗口+哈希表+matchKeys标记
        # 0、将t转换为哈希表:存储了需要匹配的字符种类及数量
        needHashTable = {}
        for ch in t:
            if ch not in needHashTable:
                needHashTable[ch] = 1
            else:
                needHashTable[ch] += 1
        # 定义滑动窗口操作的必要变量
        left, right = 0, 0
        matchKeys = 0  # 标记:与needHashTable刚好匹配或过匹配(满足覆盖条件)的键数量,即对应的元素数量 等于或大于对应的键值
        result = ""
        while right < len(s):
            # 1、当移动right扩大窗口,进行哪些操作
            if s[right] in needHashTable:
                needHashTable[s[right]] -= 1
                if needHashTable[s[right]] == 0:  # 对应的key被覆盖了
                    matchKeys += 1
                # 2、什么条件下,窗口应该暂停扩大,开始移动left缩小窗口
                while matchKeys == len(needHashTable):
                    # 4、更新结果
                    if result == "":  # 第一次有结果满足时
                        result = s[left: right+1]
                    else:
                        if len(result) > right - left + 1:
                            result = s[left: right+1]
                    # 3、缩小窗口进行哪些操作
                    if s[left] in needHashTable:
                        needHashTable[s[left]] += 1
                        if needHashTable[s[left]] == 1:  # 对应的key不被覆盖了
                            matchKeys -= 1
                    left += 1
            right += 1
        return result


if __name__ == "__main__":
    obj = Solution()
    while True:
        try:
            in_line = input().strip().split('=')
            s = in_line[1].split(',')[0].strip()[1: -1]
            t = in_line[2].strip()[1: -1]
            print(obj.minWindow(s, t))
        except EOFError:
            break
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

22世纪冲刺

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值