【总结】
该类题目包括类型为:
1.最多包含k个重复字符的连续子串:【Leetcode-3】,窗口先增加后减少,窗口增加的条件是字符已经存在(look_up[a[end]]>0),窗口减少的条件是窗口内首字符是重复(look_up[a[start]]>1)
2.最多包含k个不同字符的连续子串:【Leetcode-340】,窗口先增加后减少,窗口增加的条件是字符新出现(look_up[a[end]]==0),窗口减少的条件是窗口内首字符只有1个(look_up[a[start]]==1)
3.至少包含某些字符的连续子串:【Leetcode-76】,窗口先减少后增加,窗口减少的条件是字符是被需要的(look_up[a[end]]>0),窗口增加的条件是窗口内首字符刚好够(look_up[a[start]]==0)
4.乘积至多/至少为k的的连续子串:【Leetcode-713】
【Leetcode-3】
一、题目:无重复字符的最长子串
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
二、代码
def lengthOfLongestSubstring(self, s: str) -> int: 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-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-76】最小覆盖子串
一、题目:
给你一个字符串 s
、一个字符串 t
。返回 s
中涵盖 t
所有字符的最小子串。如果 s
中不存在涵盖 t
所有字符的子串,则返回空字符串 ""
。
二、代码:
def minWindow(self, s: 'str', t: 'str') -> 'str': 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-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