【Leetcode】滑窗系列

【总结】

1.该类题目包括类型为:1)最多包含k个重复(不重复)字符的连续子串 2)最少包含某些字符的连续子串 3)乘积/和至少/至多为k的连续子串

2.解题思路:分为最多包含和最少包含

def f(s):
    l, r = 0, 0
    look_up = {}
    counter = 0
    while r < len(s):
        look_up[s[r]] = look_up.get(s[r], 0) + 1  # 右指针填进去
        if *:  counter += 1  # 更新counter
        while *:  # 移动左指针使得满足条件
            look_up[s[l]] -= 1  # 左指针去除
            if *: counter -= 1 # 更新counter 
            l += 1
        r += 1

 

def f(s):
    l, r = 0, 0
    look_up = {}
    for item in t:
        look_up[item] = look_up.get(item, 0) + 1
    counter = len(t)
    while r < len(s):
        look_up[s[r]] = look_up.get(s[r], 0) - 1  # 右指针填进去
        if *:  counter -= 1  # 更新counter
        while *:  # 移动左指针使得不满足条件
            look_up[s[l]] += 1  # 左指针去除
            if *: counter += 1 # 更新counter
            l += 1
        r += 1

  

Leetcode-3】

一、题目:无重复字符的最长子串

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

二、代码

def lengthOfLongestSubstring(self, s: str) -> int:
        """
        look_up记录窗口里元素的数量,counter记录至少剔除几个元素才能不重复
        """
        l, r = 0, 0
        max_len = 0
        look_up = {}
        counter = 0
        while r < len(s):
            look_up[s[r]] = look_up.get(s[r], 0) + 1  # 右指针填进去
            if look_up[s[r]] > 1:  counter += 1  # 重复+1
            while counter > 0:  # 移动左指针去除重复
                look_up[s[l]] -= 1
                if look_up[s[l]] >= 1:  # 现在依然有1个,说明之前是重复
                    counter -= 1
                l += 1 
            max_len = max(r-l+1, max_len)
            r += 1
        return max_len
        """
        from collections import defaultdict
        look_up = defaultdict(int)
        i = j = window = max_val = 0
        while j <= len(s) - 1:
            if look_up[s[j]] > 0:
                window += 1
            look_up[s[j]] += 1
            j += 1
            while window > 0:
                if look_up[s[i]] > 1:
                    window -= 1
                look_up[s[i]] -= 1
                i += 1
            max_val = max(max_val, j - i)
        return max_val
        """

 

【Leetcode-76】最小覆盖子串

一、题目:

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

二、代码:

def minWindow(self, s: str, t: str) -> str:
        """
        look_up表示窗口里面需要元素的数量,counter表示最少需要的元素个数
        """
        l, r = 0, 0
        look_up = {}
        for item in t:
            look_up[item] = look_up.get(item, 0) + 1
        counter = len(t)
        res = [-1, float('inf')]  # 起点, 长度
        while r < len(s):
            look_up[s[r]] = look_up.get(s[r], 0) - 1  # 右指针填进去
            if look_up[s[r]] >= 0:  # 该元素是需要的,以后不一定需要
                counter -= 1
            while counter == 0:  # 满足条件,剔除不需要的东西
                if res[1] > r - l + 1:
                    res = [l, r - l + 1] 
                look_up[s[l]] += 1  # 需要的+1
                if look_up[s[l]] > 0:  # 踢了之后需要的元素缺少
                    counter += 1
                l += 1
            r += 1
        if res[1] < float('inf'):
            return s[res[0]: res[0]+res[1]]
        else:
            return ""
        """
        from collections import defaultdict
        lookup = defaultdict(int)
        for c in t:
            lookup[c] += 1
        start = 0
        end = 0
        min_len = float("inf")
        counter = len(t)
        res = ""
        while end < len(s):
            if lookup[s[end]] > 0:
                counter -= 1
            lookup[s[end]] -= 1
            end += 1
            while counter == 0:
                if min_len > end - start:
                    min_len = end - start
                    res = s[start:end]
                if lookup[s[start]] == 0:
                    counter += 1
                lookup[s[start]] += 1
                start += 1
        return res
        """

 

【Leetcode-159】

一、题目:至多包含两个不同字符的最长子串

  给定一个字符串 s ,找出 至多 包含两个不同字符的最长子串 t ,并返回该子串的长度。

二、代码:

def lengthOfLongestSubstringTwoDistinct(self, s: str) -> int:
        """
        滑窗,窗口先大再小,大的条件是来了新字符,小的条件是该字符只出现一次
        """
        n = len(s)
        start = end = res = window = 0
        lookup = {} 
        while end < n:
            cnt = lookup.get(s[end], 0)
            if cnt == 0:
                window += 1
            lookup[s[end]] = cnt + 1
            end += 1
            while window > 2:
                cnt = lookup.get(s[start], 0)
                if cnt == 1:
                    window -= 1
                lookup[s[start]] = cnt - 1
                start += 1
            # 满足条件
            res = max(res, end-start)
        return res

 

【Leetcode-340】

一、题目:至多包含k个不同字符的最长子串

  给定一个字符串 s ,找出 至多 包含 k 个不同字符的最长子串 T

二、代码:

def lengthOfLongestSubstringKDistinct(self, s: str, k: int) -> 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 > k:
                if lookup[s[start]] == 1:
                    counter -= 1
                lookup[s[start]] -= 1
                start += 1
            max_len = max(max_len, end - start)
        return max_len

 

【Leetcode-713】

一、题目:乘积小于K的子数组

  给定一个正整数数组 nums

  找出该数组内乘积小于 k 的连续的子数组的个数。

二、代码:

def numSubarrayProductLessThanK(self, nums: List[int], k: int) -> int:
        """
        前缀积,0~i的乘积为si,前缀积记录在look,则截止到i(包括i),<k的连续子数组数为look中key>si/k的数量之和+自身是否>k
        !当数值可能较大时,前缀积也较大,可能无法计算,因此该方法只能数值小时使用!
        if k == 0:
            return 0
        look = {1: 1}
        pre_multi = 1
        res = 0
        for item in nums:
            pre_multi *= item
            # 前面提供的
            for pre, ct in look.items():
                if pre > pre_multi/k:
                    res += ct 
            # 更新
            cnt = look.get(pre_multi, 0)
            look[pre_multi] = cnt + 1
        return res
        """
        """
        滑窗
        """
        if k <= 1:
            return 0
        accumulate = 1  # 窗口内的积
        n = len(nums)
        res = 0
        start, end = 0, 0  # 窗口两端,结果需要包含end
        while end < n:
            accumulate *= nums[end]
            end += 1
            while accumulate >= k:
                accumulate /= nums[start]
                start += 1
            # 此刻满足条件,记录个数
            res += (end - start)  # start~end-1间,包含end的子数组个数
        return res

 

posted @ 2021-04-01 20:18  我若成风者  阅读(114)  评论(0编辑  收藏  举报