今天分享一些滑动窗口的题目以及对应的题解
1.长度最小的子数组 Leetcode#209
题目:给定一个含有 n 个正整数的数组和一个正整数 target 。
找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, …, numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。
输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。
输入:target = 4, nums = [1,4,4]
输出:1
输入:target = 11, nums = [1,1,1,1,1,1,1,1]
输出:0
提示:
1 <= target <= 109
1 <= nums.length <= 105
1 <= nums[i] <= 105
class Solution:
def minSubArrayLen(self, target: int, nums: List[int]) -> int:
n = len(nums)
sums = left = 0
minsize = float("inf")
for right in range(n):
sums += nums[right]
while sums >= target:
minsize = min(minsize,right-left+1)
sums -= nums[left]
left += 1
return minsize if minsize != float("inf") else 0
这算是一道经典的滑动窗口题了,通过sums来记录和,然后判断这个和是否大于等于target,如果条件成立的话就更新minsize,并且减去nums中左指针对应的值,且左指针向右一格,循环结果就可以输出结果了。题目所给的值都是大于0的,所以和一直是增加的,如果有负数这么做就不行了。
2. 无重复字符的最长子串 Leetcode#3
题目:给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
输入: s = “abcabcbb”
输出: 3
解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。
输入: s = “bbbbb”
输出: 1
解释: 因为无重复字符的最长子串是 “b”,所以其长度为 1。
输入: s = “pwwkew”
输出: 3
解释: 因为无重复字符的最长子串是 “wke”,所以其长度为 3。
请注意,你的答案必须是 子串 的长度,“pwke” 是一个子序列,不是子串。
输入: s = “”
输出: 0
提示:
0 <= s.length <= 5 * 104
s 由英文字母、数字、符号和空格组成
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
n = len(s)
res = left = 0
counter = collections.Counter()
for right in range(n):
counter[s[right]] += 1
while counter[s[right]] > 1:
counter[s[left]] -=1
left += 1
res = max(res,right-left+1)
return res
通过一个集合来记录字符出现的次数,每次出现都记录,然后判断之前是否记录过,记录过就删除集合中左指针对应的字符,并且左指针往右移动一格,直到这个字符在整个集合中只出现过一次,并且更新结果,循环结束即输出结果。
3. 至多包含两个不同字符的最长子串Leetcode#159
题目:给定一个字符串 s ,找出 至多 包含两个不同字符的最长子串 t ,并返回该子串的长度。
输入: “eceba”
输出: 3
解释: t 是 “ece”,长度为3。
输入: “ccaabbb”
输出: 5
解释: t 是 “aabbb”,长度为5。
class Solution:
def lengthOfLongestSubstringTwoDistinct(self, s: str) -> int:
n = len(s)
res = left = 0
counter = collections.Counter()
for right in range(n):
counter[s[right]] += 1
while len(counter) > 2:
counter[s[left]] -= 1
if counter[s[left]] == 0:
counter.pop(s[left])
left += 1
res = max(res,right-left+1)
return res
这一题与上一题类型。只是上一题是无重复的,所以集合中某个值出现的次数大于1就需要调整,而这一题不再是某个值重复出现,而是只能有小于等于两个不同的值出现,一旦集合中出现了三个不同的值,那么集合中左指针对应的值需要减1,如果这个值出现的次数为0就删除它(也就是集合中没有这个值了,也是为什么上面用len()的原因),并且左指针向右移动一格,直到集合中只有两个及两个以内的不同值,最后输出最长的长度即可。
4.至多包含 K 个不同字符的最长子串Leetcode#340
题目:给定一个字符串 s ,找出 至多 包含 k 个不同字符的最长子串 T。
输入: s = “eceba”, k = 2
输出: 3
解释: 则 T 为 “ece”,所以长度为 3。
输入: s = “aa”, k = 1
输出: 2
解释: 则 T 为 “aa”,所以长度为 2。
class Solution:
def lengthOfLongestSubstringKDistinct(self, s: str, k: int) -> int:
res = left = 0
counter = collections.Counter()
for right in range(len(s)):
counter[s[right]] += 1
while len(counter) > k:
counter[s[left]] -= 1
if counter[s[left]] == 0:
counter.pop(s[left])
left += 1
res = max(res, right-left+1)
return res
这段代码和上一题只有一处不一样,上一题是最多包含两个,这一题则变为了k个,其他的则不变。
5.K 个不同整数的子数组Leetcode#992
题目:给定一个正整数数组 A,如果 A 的某个子数组中不同整数的个数恰好为 K,则称 A 的这个连续、不一定独立的子数组为好子数组。
(例如,[1,2,3,1,2] 中有 3 个不同的整数:1,2,以及 3。)
返回 A 中好子数组的数目。
输入:A = [1,2,1,2,3], K = 2
输出:7
解释:恰好由 2 个不同整数组成的子数组:[1,2], [2,1], [1,2], [2,3], [1,2,1], [2,1,2], [1,2,1,2].
输入:A = [1,2,1,3,4], K = 3
输出:3
解释:恰好由 3 个不同整数组成的子数组:[1,2,1,3], [2,1,3], [1,3,4].
class Solution:
def subarraysWithKDistinct(self, A: List[int], K: int) -> int:
def atmostK(K):
n = len(A)
res = left = 0
counter = collections.Counter()
for right in range(n):
counter[A[right]] += 1
while len(counter) > K:
counter[A[left]] -= 1
if counter[A[left]] == 0:
counter.pop(A[left])
left += 1
res += right - left + 1
return res
return atmostK(K) - atmostK(K-1)
这段代码和之前的代码有相似的地方,也是通过一格集合来记录值出现的次数,如果不同值出现的次数超过k了,那么就将他移除。不同的是这题需要求子数组个数,之前的题目则是求最长的字串。这题K个不同整数的子数组个数=最多有K个不同整数的子数组的个数-最多有K-1个不同整数的子数组的个数
举个例子:对于 A = [1,2,1,2,3], K = 2,我们运行上面的代码过程中,会得到的两个满足题意的子数组 [1, 2, 1, 2]和[2, 3]。
对于子数组[1, 2, 1, 2],它的所有子数组都是满足题意的,共有 1 + 2 + 3 + 4 = 10 个子数组。
以第一个 1 为右端点的满足题意的子数组为 [1];
以第一个 2 为右端点的满足题意的子数组为 [1,2], [2];
以第二个 1 为右端点的满足题意的子数组为 [1,2,1],[2,1], [1];
以第二个 2 为右端点的满足题意的子数组为 [1,2,1,2], [2,1,2],[1,2], [2];
对于子数组[2, 3],它的所有子数组都满足题意,共有 3 个子数组。
以 2 为右端点的满足题意的子数组,在上面已经统计过了,因此不要重复统计。
以 3 为右端点的满足题意的子数组为[2, 3], [3],看不太懂可以按照索引来计算一下会比较清楚。
所以这里最多有两个不同整数的子数组个数为12个,最多有1个不同整数的子数组个数为5个,所以2个不同整数的子数组个数=12-5=7