之前做的题,都是问区间最长长度或者最优结果,但这次返回的是满足条件得区间个数,就不能用之前的思路了,因为可能会忽略情况。
第一种解法就是,在左指针移动前,先记录下满足条件的个数,代码如下:
class Solution:
def subarraysWithKDistinct(self, A: List[int], K: int) -> int:
l, r, ret = 0, 0, 0
c = Counter()
while r < len(A):
c[A[r]] += 1
# 移动左指针
while l<=r and len(c) > K:
c[A[l]] -= 1
if c[A[l]] == 0: del c[A[l]]
l += 1
# # 统计信息
tmp = l
s = []
while tmp<=r and len(c) == K:
ret += 1
s.append(A[tmp])
c[A[tmp]] -= 1
if c[A[tmp]] == 0: del c[A[tmp]]
tmp += 1
for t in s:
c[t] += 1
r += 1
return ret
还是之前的双指针模板,但是加了一个O(ret)的复杂度,已经不是O(N)了,速度慢。
解法二:两次遍历
这是一个O(N)的很强的解法。要写一个函数,返回满足条件得子区间的所有子区间。比如[1, 2, 3, 3, 5], 3 例子中,[1, 2, 3, 3] 和 [2, 3, 3, 5] 是满足条件得,他们两个的子区间个数是可以在右指针移动过程中计算的,1+2+3+4。但这里面包含小于K的情况,再调用K-1,即可把这部分可能性排除,代码如下:
class Solution:
def subarraysWithKDistinct(self, A: List[int], K: int) -> int:
def getSubArray(A, K):
l, r, ret = 0, 0, 0
c = Counter()
while r < len(A):
c[A[r]] += 1
while l <= r and len(c) > K:
c[A[l]] -= 1
if c[A[l]] == 0: del c[A[l]]
l += 1
ret += r-l+1
r += 1
return ret
return getSubArray(A, K) - getSubArray(A, K-1)
这个题很不一样的一点在于,要求不同的数字数目必须为K,而我们需要转化为<=K才能用双指针移动。