leetcode刷题记录 - 滑动窗口

https://labuladong.online/algo/essential-technique/sliding-window-framework/

1. 框架

# 滑动窗口算法框架
def slidingWindow(s: str):
    # 用合适的数据结构记录窗口中的数据,根据具体场景变通
    # 比如说,我想记录窗口中元素出现的次数,就用 map
    # 我想记录窗口中的元素和,就用 int
    window = dict()
    
    left = 0
    right = 0
    while right < len(s):
        # c 是将移入窗口的字符
        c = s[right]
        window[c] = window.get(c, 0) + 1
        # 增大窗口
        right += 1
        # 进行窗口内数据的一系列更新
        #...

        #/*** debug 输出的位置 ***/
        # 注意在最终的解法代码中不要 print
        # 因为 IO 操作很耗时,可能导致超时
        # print(f"window: [{left}, {right})")
        #/********************/

        # 判断左侧窗口是否要收缩
        while left < right and "window needs shrink":
            # d 是将移出窗口的字符
            d = s[left]
            window[d] -= 1
            if window[d] == 0:
                del window[d]
            # 缩小窗口
            left += 1
            # 进行窗口内数据的一系列更新
            #...

2. 最小覆盖子串

class Solution(object):
    def minWindow(self, s, t):
        """
        :type s: str
        :type t: str
        :rtype: str
        """
        n = len(s)
        if n == 0:
            return ""
        # 用来判断当前窗口是否满足条件
        valid_bit = 0

        window_dict = {}
        target_dict = {}
        start, final_len = 0, n+1
        for c in t:
            if c in target_dict.keys():
                target_dict[c] += 1
            else:
                target_dict[c] = 1
        lo, hi = 0, 0

        while hi < n:
            ch = s[hi]
            hi += 1
            if ch in target_dict.keys():
                if ch not in window_dict.keys():
                    window_dict[ch] = 1
                else:
                    window_dict[ch] += 1
                if window_dict[ch] == target_dict[ch]:
                    valid_bit += 1 
              
            while valid_bit == len(target_dict):
                if hi -lo < final_len:
                    final_len = hi - lo
                    start = lo
                ch = s[lo]
                lo += 1
                if ch in target_dict.keys():
                    window_dict[ch] -= 1
                    if window_dict[ch] < target_dict[ch]:
                        valid_bit -= 1                     
        
        if final_len == n+1:
            return ""
        else:
            return s[start:start+final_len]

3. 找到字符串中的所有字母异位词

https://leetcode.cn/problems/find-all-anagrams-in-a-string/description/
这道题可以按照上面,先扩右边再收缩左边;但第一反应想到的是固定长度的滑动窗口,每次直接lo++ hi++。
但是这里两个地方容易出错:

  1. len(s) < len§的时候会报错
  2. 要先在while循环外判断一次valid,然后在每次while结束的时候判断valid,有点繁琐,容易写错
class Solution(object):
    def findAnagrams(self, s, p):
        """
        :type s: str
        :type p: str
        :rtype: List[int]
        """
        def putChar(d, c):
            if c in d:
                d[c] += 1
            else:
                d[c] = 1                
        res = []
        if not s or len(s) < len(p):
            return res        
        valid = 0
        lo, hi = 0, len(p)
        target_dict = {}
        window_dict = {}
        for c in p:
            putChar(target_dict, c)
        for i in range(lo, hi):
            if s[i] in p:
                putChar(window_dict, s[i])
                if window_dict[s[i]] == target_dict[s[i]]:
                    valid += 1     
        if valid == len(target_dict):
            res.append(lo)
        while hi < len(s):         
            if s[lo] in window_dict:
                if window_dict[s[lo]] == target_dict[s[lo]]:
                    valid -= 1
                window_dict[s[lo]] -= 1

            if s[hi] in target_dict:
                putChar(window_dict, s[hi])
                if window_dict[s[hi]] == target_dict[s[hi]]:
                    valid += 1
            lo += 1
            hi += 1 
            if valid == len(target_dict):
                res.append(lo)
        return res        

再用先扩后缩的框架写一遍,这种方式更不容易出错

class Solution(object):
    def findAnagrams(self, s, p):
        """
        :type s: str
        :type p: str
        :rtype: List[int]
        """
        def putChar(d, c):
            if c in d:
                d[c] += 1
            else:
                d[c] = 1                
        res = []
        if not s:
            return res        
        valid = 0
        lo, hi = 0, 0
        target_dict = {}
        window_dict = {}
        for c in p:
            putChar(target_dict, c)
        while hi < len(s): 
            ch = s[hi]  
            hi += 1
            if ch in target_dict:      
                putChar(window_dict, ch)
                if window_dict[ch] == target_dict[ch]:
                    valid += 1

            while valid == len(target_dict):
                if hi - lo == len(p):
                    res.append(lo)
                start = lo
                ch = s[lo]
                if ch in target_dict:
                    window_dict[ch] -= 1
                    if window_dict[ch] < target_dict[ch]:
                        valid -= 1
                lo += 1
        return res

4 无重复字符的最长子串

这个直接套框架
https://leetcode.cn/problems/longest-substring-without-repeating-characters/description/

class Solution(object):
    def lengthOfLongestSubstring(self, s):
        """
        :type s: str
        :rtype: int
        """
        if not s:
            return 0
        window_dict = {}
        lo, hi = 0, 0
        res = 0
        while hi < len(s):
            c = s[hi]
            hi += 1
            if c not in window_dict or window_dict[c] == 0:
                window_dict[c] = 1
                res = max(res, hi - lo)
            else:
                window_dict[c] += 1

            while window_dict[c] > 1:
                c2 = s[lo]
                window_dict[c2] -= 1
                lo += 1

        return res
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值