【滑动窗口】LeetCode题集

滑动窗口的动态演示:

【力扣209题】
给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的连续子数组。如果不存在符合条件的连续子数组,返回 0。

示例: 

输入: s = 7, nums = [2,3,1,2,4,3]
输出: 2
解释: 子数组 [4,3] 是该条件下的长度最小的连续子数组。

滑动窗口演示图
在这里插入图片描述
演示题解代码:


def minSubArrayLen(s: int, nums: List[int]) -> int:
    summation = 0
    L, R = 0, -1
    optim = len(nums) + 1
    while R < len(nums):
        while R < len(nums):
            R += 1
            if R < len(nums):
                summation += nums[R]
            if summation >= s:
                optim = min(optim, R - L + 1)
                break

        if R == len(nums):
            break

        while L < R:
            summation -= nums[L]
            L += 1
            if summation >= s:
                optim = min(optim, R - L + 1)
            else:
                break
    return optim if optim != len(nums) + 1 else 0

力扣第3题:
无重复字符的最长子串

上题的模板可以总结为:

初始化窗口端点L,R,一般L为0,R为1
    初始化最优值
    while R < len(Array):
        while R < len(Array):
            R += 1              #移动右端点
            if R < len(Array):
                更新状态        
            if 状态满足条件:
                可选的更新最优值的位置
                break           #一旦满足条件即跳出
        if R == len(Array):     # 若循环是由于移动到数组末尾结束,则停止整个程序。因为之后已经不再有可能的解
            break
        while L < R:
            更新状态    # 移动左端点,需要更新状态
            L += 1
            if 状态满足条件:
                可选的更新最优值的位置
            else# 一旦窗口所在区间不再满足条件即跳出,去移动右端点
                break
        可选的对于L,R端点的后续处理
    return 最优值

用以上模板可以写出相应的题解(无重复元素的最长子串):

def lengthOfLongestSubstring(s: str) -> int:
    L, R = 0, -1
    optim = 0
    status = set()
    while R < len(s):
        while R < len(s):
            R += 1
            if R == len(s):
                break
            if s[R] not in status:
                status.add(s[R])
                optim = max(optim, R - L + 1)
            else:
                break

        if R == len(s):
            break

        while L < R:
            if s[L] != s[R]:
                status.remove(s[L])
                L += 1
            else:
                L += 1
                break
    return optim

茴香豆的四种写法:
力扣3题的另外相关模板集合:
模板1:使用defaultdict

class Solution:
    def lengthOfLongestSubstring(self, s):
        """
        :type s: str
        :rtype: int
        """
        from collections import defaultdict
        lookup = defaultdict(int)
        start = 0
        end = 0
        max_len = 0
        counter = 0
        while end < len(s):
            if lookup[s[end]] > 0:
                counter += 1
            lookup[s[end]] += 1
            end += 1
            while counter > 0:
                if lookup[s[start]] > 1:
                    counter -= 1
                lookup[s[start]] -= 1
                start += 1
            max_len = max(max_len, end - start)
        return max_len

模板2:用hashmap

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        # Step 1: 定义需要维护的变量, 本题求最大长度,所以需要定义max_len, 该题又涉及去重,因此还需要一个哈希表
        max_len, hashmap = 0, {}

        # Step 2: 定义窗口的首尾端 (start, end), 然后滑动窗口
        start = 0
        for end in range(len(s)):
            # Step 3
            # 更新需要维护的变量 (max_len, hashmap)
            # i.e. 把窗口末端元素加入哈希表,使其频率加1,并且更新最大长度
            hashmap[s[end]] = hashmap.get(s[end], 0) + 1
            if len(hashmap) == end - start + 1:
                max_len = max(max_len, end - start + 1)
            
            # Step 4: 
            # 根据题意,  题目的窗口长度可变: 这个时候一般涉及到窗口是否合法的问题
            # 这时要用一个while去不断移动窗口左指针, 从而剔除非法元素直到窗口再次合法
            # 当窗口长度大于哈希表长度时候 (说明存在重复元素),窗口不合法
            # 所以需要不断移动窗口左指针直到窗口再次合法, 同时提前更新需要维护的变量 (hashmap)
            while end - start + 1 > len(hashmap):
                head = s[start]
                hashmap[head] -= 1
                if hashmap[head] == 0:
                    del hashmap[head]
                start += 1
        # Step 5: 返回答案 (最大长度)
        return max_len

力扣1004. 最大连续1的个数 III最大连续1的个数
用上述第一个模板,三个while循环,只需要找到关键的条件即可(即>=0),不满足则break

def longestOnes(A: List[int], K: int) -> int:
    L, R = 0, -1
    optim = 0
    while R < len(A):
        while R < len(A):
            R += 1
            if R == len(A):
                break
            if A[R] == 0:
                K -= 1
            if K < 0:   #第一次不满足条件
                break
            else:   #满足条件时更新最优值
                optim = max(optim, R - L + 1)

        if R == len(A):
            break

        while L < R:
            if A[L] == 0:
                K += 1
            L += 1
            if K >= 0:
                break
    return optim

力扣76题(困难):最小覆盖子串76
题解1

class Solution:
    def minWindow(self, s: str, t: str) -> str:
        need = collections.defaultdict(int) # 记录t中字符出现次数
        window = collections.defaultdict(int) # 记录窗口中响应的字符出现的次数
        for c in t:
            need[c] += 1
        
        left,right = 0,0 # 初始窗口长度为0
        valid = 0 # 用于记录window中t中字符是否出现完,比如:t='abc',window='abd',valid就等于2.代表need中应该出现的字符在window中才出现了两个,还没有出现完全

        # 记录最小覆盖子串的起始索引及长度
        start = 0
        length = len(s) + 1

        while right < len(s):
            c = s[right] # 即将加入window的字符c
            right += 1 # 右移窗口

            # 窗口内数据的一系列更新
            if c in need:
                window[c] += 1
                if window[c] == need[c]: # window中字符c出现的次数已经达到need所需要的次数时,valid进行更新
                    valid += 1

            # 判断窗口左侧边界是否要收缩
            while valid == len(need):
                # 在这里更新最小覆盖子串
                if right-left < length:
                    start = left
                    length = right-left

                # d是将移出窗口的字符
                d = s[left]
                # 左移窗口
                left += 1
                # 进行窗口内数据的一系列更新
                if d in need:
                    if window[d] == need[d]: # 这句话和下面的window[c]-=1不能反,先判断删去的字符c的数量是不是满足need的数量,如果满足,valid将减去1。
                        valid -= 1
                    window[d] -= 1
        # 返回最小覆盖子串
        if length == len(s) + 1:
            return ''
        else:
            return s[start:start+length]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
滑动窗口是一种常用的算法技巧,可以用于解决一类问题,其中包括一些LeetCode上的题目。通过维护一个窗口,我们可以在线性时间内解决一些需要处理连续子数组或子字符串的问题。以下是一些常见的滑动窗口问题: 1. 最小覆盖子串(Minimum Window Substring):给定一个字符串S和一个字符串T,在S中找出包含T所有字符的最小子串。 2. 字符串的排列(Permutation in String):给定两个字符串s1和s2,判断s2是否包含s1的排列。 3. 找到字符串中所有字母异位词(Find All Anagrams in a String):给定一个字符串s和一个非空字符串p,找到s中所有是p的字母异位词的子串。 4. 替换后的最长重复字符(Longest Repeating Character Replacement):给定一个只包含大写英文字母的字符串s,你可以将一个字母替换成任意其他字母,使得包含重复字母的最长子串的长度最大化。 5. 至多包含两个不同字符的最长子串(Longest Substring with At Most Two Distinct Characters):给定一个字符串s,找出至多包含两个不同字符的最长子串的长度。 以上只是几个例子,滑动窗口可以应用于更多类型的问题。在解决这些问题时,我们通常使用两个指针来表示窗口的左右边界,并根据具体问题的要求移动窗口。在每次移动窗口时,我们可以更新窗口的状态,例如统计字符出现次数、判断窗口是否满足条件等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值