问题描述 小M有一个由正整数组成的数组 nums,她想知道其中有多少子数组可以被称为「好子数组」。一个子数组被称为「好子数组」是指它包含的不同整数个数恰好为 k。 例如,对于数组 [1, 2, 3, 1, 2],其中包含 3 个不同的整数:1、2 和 3。 子数组指的是数组的连续部分。小M需要找出所有满足条件的子数组,并计算它们的数量。
测试样例 样例1: 输入:nums = [1, 2, 1, 2, 3],k = 2 输出:7 样例2: 输入:nums = [1, 2, 1, 3, 2],k = 3 输出:5 样例3: 输入:nums = [1, 1, 1, 1],k = 1
def solution(nums: list, k: int) -> int: n = len(nums) count = 0
for i in range(n):
distinct_nums = set()
for j in range(i, n):
distinct_nums.add(nums[j])
if len(distinct_nums) == k:
count += 1
elif len(distinct_nums) > k:
break
return count
if __name__ == '__main__':
print(solution(nums=[1, 2, 1, 2, 3], k=2) == 7)
print(solution(nums=[1, 2, 1, 3, 2], k=3) == 5)
print(solution(nums=[1, 1, 1, 1], k=1) == 10)
在上述代码中:
-
我们使用两层循环来遍历所有可能的子数组。外层循环
i确定子数组的起始位置,内层循环j从起始位置i开始逐步扩展子数组的末尾位置。 -
对于每个子数组,我们使用一个集合
distinct_nums来记录其中出现的不同整数。当集合中不同整数的个数等于k时,就找到了一个满足条件的好子数组,此时计数器count加 1。如果不同整数的个数超过了k,就无需继续扩展该子数组了,直接进入下一个起始位置i的循环。 -
最后,返回计数器
count的值,即为满足条件的好子数组的数量。 -
不过,这种方法的时间复杂度是 ,在某些情况下可能效率不高。我们可以进一步优化,使用哈希表和双指针的方法来将时间复杂度降低到 ,以下是优化后的代码:
收起
python
复制
from typing import List
def solution(nums: List[int], k: int) -> int:
n = len(nums)
count = 0
left = 0
right = 0
distinct_count = 0
num_count = {}
while right < n:
if nums[right] not in num_count:
num_count[nums[right]] = 1
distinct_count += 1
else:
num_count[nums[right]] += 1
while distinct_count > k:
num_count[nums[left]] -= 1
if num_count[nums[left]] == 0:
distinct_count -= 1
del num_count[nums[left]]
left += 1
if distinct_count == k:
count += right - left + 1
right += 1
return count
在优化后的代码中:
- 我们使用双指针
left和right来表示滑动窗口的左右边界。 num_count是一个哈希表,用于记录每个数字在当前窗口中出现的次数。distinct_count则记录当前窗口中不同数字的个数。- 当右指针
right向右移动时,我们更新num_count和distinct_count。如果distinct_count超过了k,我们通过移动左指针left来缩小窗口,直到distinct_count等于k为止。 - 当
distinct_count等于k时,满足条件的子数组数量就增加right - left + 1,因为从left到right的这个窗口内的所有子数组(以left为起始位置,长度从 1 到right - left + 1)都满足条件。 - 最后返回
count,就是满足条件的好子数组的总数。这种优化后的方法时间复杂度为 ,其中n是数组nums的长度,在处理较大规模的数组时效率更高。