满足一定条件的最长子串[或者子数组]问题,典型题可以参考leetcode159和904,如下。
leetcode 159至多包含两个不同字符的最长子串;
给定一个字符串 s ,找出 至多 包含两个不同字符的最长子串 t ,并返回该子串的长度。
示例 1:
输入: “eceba”
输出: 3
解释: t 是 “ece”,长度为3。
leetcode 904水果成篮
你正在探访一家农场,农场从左到右种植了一排果树。这些树用一个整数数组 fruits 表示,其中 fruits[i] 是第 i 棵树上的水果 种类 。
你想要尽可能多地收集水果。然而,农场的主人设定了一些严格的规矩,你必须按照要求采摘水果:
你只有 两个 篮子,并且每个篮子只能装 单一类型 的水果。每个篮子能够装的水果总量没有限制。
你可以选择任意一棵树开始采摘,你必须从 每棵 树(包括开始采摘的树)上 恰好摘一个水果 。采摘的水果应当符合篮子中的水果类型。每采摘一次,你将会向右移动到下一棵树,并继续采摘。
一旦你走到某棵树前,但水果不符合篮子的水果类型,那么就必须停止采摘。
给你一个整数数组 fruits ,返回你可以收集的水果的 最大 数目。
示例 1:
输入:fruits = [1,2,1]
输出:3
解释:可以采摘全部 3 棵树。
示例 2:
输入:fruits = [0,1,2,2]
输出:3
解释:可以采摘 [1,2,2] 这三棵树。
如果从第一棵树开始采摘,则只能采摘 [0,1] 这两棵树。
示例 3:
输入:fruits = [1,2,3,2,2]
输出:4
示例 4:
输入:fruits = [3,3,3,1,2,1,1,2,3,3,4]
输出:5
解释:可以采摘 [1,2,1,1,2] 这五棵树。
从求 子串最长长度 到 子串最多个数
上面两道题基本一样 代码如下
class Solution:
def lengthOfLongestSubstringTwoDistinct(self, s: str) -> int:
n = len(s)
char_count={} # key:字符 value:字符个数
l=0
res=0
for r in range(n):
char_count[s[r]]=char_count.get(s[r],0)+1
if len(char_count)<=2: #最多只有两种字符 在此情况找最长字符
res=max(res, r-l+1)
while len(char_count)>2:# # l右移直到只有两种字符,同时更新字典
char_count[s[l]]-=1
if char_count[s[l]]==0:
del char_count[s[l]]
l+=1
return res
上面两题核心都是求res=max(res, r-l+1),即最多只包含k个不同整数的子序列最长长度。
如果问 A 中由最多 K 个不同整数组成的子数组的个数,该怎么办呢?
当满足len(char_count)<=k的时候,l到r区间的内,所有子数组都是满足条件的,这些子数组都是都是最多k个不同整数组成。
但是区间是动态变化的,也就是l和r动态变化,我们如果直接数出l到r之间子数组的个数,那这样可能会重复计数。
因此,这里我们考虑用leetcode 467 和 leetcode 795里面的计数思路。
res表示之前满足条件的个数,curr_num满足当前循环内满足条件的个数,具体的,curr_num表示满足条件的,并且以r为结尾的子数组,这样每一轮我们都有
res+=curr_num,也就是只需要求出每一轮的curr_num即可。
所以在上述问题中,求l到r区间内,以r为结尾的,最多k个不同整数组成的子数组个数,数值上就是区间长度r-l+1。
所以res=res+curr_num = res+r-l+1
leetcode 992 K 个不同整数的子数组
给定一个正整数数组 nums和一个整数 k ,返回 num 中 「好子数组」 的数目。
如果 nums 的某个子数组中不同整数的个数恰好为 k,则称 nums 的这个连续、不一定不同的子数组为 「好子数组 」。
例如,[1,2,3,1,2] 中有 3 个不同的整数:1,2,以及 3。
子数组 是数组的 连续 部分。
示例 1:
输入:nums = [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].
示例 2:
输入:nums = [1,2,1,3,4], k = 3
输出:3
解释:恰好由 3 个不同整数组成的子数组:[1,2,1,3], [2,1,3], [1,3,4].
class Solution:
def atMost(self, nums, k):
#某个子数组中的整数不大于k,求满足条件的子数组的个数
n=len(nums)
l,res = 0,0
val_count={}
for r in range(n):
val_count[nums[r]]=val_count.get(nums[r],0)+1
while len(val_count)>k:
val_count[nums[l]]-=1
if val_count[nums[l]]==0:
del val_count[nums[l]]
l+=1
if len(val_count)<=k: # 注意这里的if需要在while循环后面,因为需要在l变化之后计数
res+=r-l+1
# print(res,r,l)
return res
def subarraysWithKDistinct(self, nums: List[int], k: int) -> int:
return self.atMost(nums,k) -self.atMost(nums,k-1)