滑动窗口刷题指南

文章目录

    • 一、滑动窗口解题框架
    • 二、刷题指南
        • 1、最小覆盖子串
        • 2、找到字符串中所有字母异位词
        • 3、无重复字符的最长子串
        • 4、字符串的排列

一、滑动窗口解题框架

# 滑动窗口算法框架
class Solution:
    def slidingWindow(self, s: str, p: str):
		left = right = 0
        needs, window = {}, {}
        match = 0
        for v in p: needs[v] = needs.get(v, 0) + 1
        while right < len(s):
            cur = s[right]
            
            # 进行窗口内数据的一系列更新
            if needs.get(cur):
                window[cur] = window.get(cur, 0) + 1
                if window[cur] == needs[cur]: match += 1
            
            right += 1
            # 判断左侧窗口是否要收缩
            while (window needs shrink):
                # 当窗口符合条件时,执行相应操作

                cur = s[left]
                
                # 进行窗口内数据的一系列更新
                if needs.get(cur):
                    if window[cur] == needs[cur]: match -= 1
                    window[cur] -= 1
                
                left += 1

二、刷题指南

1、最小覆盖子串

给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 “” 。

注意:

  • 对于 t 中重复字符,我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量。
  • 如果 s 中存在这样的子串,我们保证它是唯一的答案。

示例 1:

输入:s = "ADOBECODEBANC", t = "ABC"
输出:"BANC"
解释:最小覆盖子串 "BANC" 包含来自字符串 t 的 'A''B''C'
import math
class Solution:
    def minWindow(self, s: str, t: str) -> str:
        left = right = 0
        needs, window = {}, {}
        smallest_len, smallest_str = math.inf, ""
        # 记录 window 中已经有多少字符符合要求了
        match = 0
        for v in t: needs[v] = needs.get(v, 0) + 1
        while right < len(s):
            cur = s[right]
            if needs.get(cur):
                window[cur] = window.get(cur, 0) + 1
                # 注意这里是 ==, 不是>=, 因为match是算A、B、C存在即符合条件
                # 如果>=,两个B一个C没有A, match也是3,但其实只有一个A、一个B、一个C才算match
                if window[cur] == needs[cur]: match += 1
            # 注意这里的right其实是多加了1的
            right += 1 
            while match == len(needs):
                # 因为上面right多加1,因此原本这里的right - left + 1, 这里只需要right - left即可
                cur_len = right - left
                if cur_len < smallest_len:
                    smallest_len = cur_len
                    # 因为上面right多加1,因此原本这里的s[left:right + 1], 这里只需要s[left:right]即可
                    smallest_str = s[left:right]
                cur = s[left]
                if needs.get(cur):
                    if window[cur] == needs[cur]: match -= 1
                    window[cur] -= 1
                left += 1
        return smallest_str

2、找到字符串中所有字母异位词

给定两个字符串 s 和 p,找到 s 中所有 p 的 异位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。

异位词 指由相同字母重排列形成的字符串(包括相同的字符串)。

示例 1:

输入: s = "cbaebabacd", p = "abc"
输出: [0,6]
解释:
起始索引等于 0 的子串是 "cba", 它是 "abc" 的异位词。
起始索引等于 6 的子串是 "bac", 它是 "abc" 的异位词。
class Solution:
    def findAnagrams(self, s: str, p: str) -> List[int]:
        left = right = 0
        needs, window = {}, {}
        res = []
        match = 0 
        for v in p: needs[v] = needs.get(v, 0) + 1
        while right < len(s):
            cur = s[right]
            # 进行窗口内数据的一系列更新
            if needs.get(cur):
                window[cur] = window.get(cur, 0) + 1
                if window[cur] == needs[cur]: match += 1
            right += 1
            # 判断左侧窗口是否要收缩
            # 这个题比较特殊可以直接if, 也可以和解题框架保持一致使用:while (right - left) == len(p):
            if (right - left) == len(p):
                # 当窗口符合条件时,把起始索引加入 res
                if match == len(needs):
                    res.append(left)
                cur = s[left]
                # 进行窗口内数据的一系列更新
                if needs.get(cur):
                    if window[cur] == needs[cur]: match -= 1
                    window[cur] -= 1
                left += 1
        return res

3、无重复字符的最长子串

给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。

示例 1:

输入: s = "abcabcbb"
输出: 3 
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3
class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        left = right = 0
        window = {}
        longest_len = 0
        while right < len(s):
            r = s[right]
            window[r] = window.get(r, 0) + 1
            right += 1
            while window[r] > 1:
                l = s[left]
                window[l] -= 1
                left += 1
            # 没有重复的才计算最大长度
            cur_len = right - left
            longest_len = max(cur_len, longest_len)
        return longest_len

4、字符串的排列

给你两个字符串 s1 和 s2 ,写一个函数来判断 s2 是否包含 s1 的排列。如果是,返回 true ;否则,返回 false 。

换句话说,s1 的排列之一是 s2 的 子串 。
示例 1:

输入:s1 = "ab" s2 = "eidbaooo"
输出:true
解释:s2 包含 s1 的排列之一 ("ba").
class Solution:
    def checkInclusion(self, s1: str, s2: str) -> bool:
        left = right = 0
        needs, window = {}, {}
        flag = False
        match = 0
        for v in s1: needs[v] = needs.get(v, 0) + 1
        while right < len(s2):
            r = s2[right]
            if needs.get(r):
                window[r] = window.get(r, 0) + 1
                if window[r] == needs[r]: match += 1
            right += 1
            if (right - left) == len(s1):
                if match == len(needs):
                    flag = True
                    break
                l = s2[left]
                if needs.get(l):
                    if window[l] == needs[l]: match -= 1
                    window[l] -= 1
                left += 1
        return flag

你可能感兴趣的:(LeetCode刷题,算法)