题目:小A拿到了一个长度为n的数组,并且定义了一个连续子数组的“权值”为该子数组内不同元素的个数。现在,她想知道,权值分别为1,2,3,…,n的子数组数量有多少个。 你需要根据给定的数组,输出一个包含n个整数的数组,第i个数表示权值为i的子数组数量。
- 解题思路:
- 我们可以使用双指针(滑动窗口)的方法来解决这个问题。通过移动左右指针来不断扩展和收缩子数组,同时统计不同元素的个数,也就是子数组的“权值”。
- 首先,初始化两个指针 left 和 right 都指向数组的开头,然后逐步移动 right 指针来扩大子数组的范围。
- 在移动 right 指针的过程中,我们使用一个字典(或者集合)来记录已经出现过的元素,以便快速判断子数组内不同元素的个数。
- 当子数组的权值达到我们想要统计的某个值 i 时,记录下此时满足权值为 i 的子数组数量。然后通过移动 left 指针来收缩子数组,继续寻找下一个满足条件的子数组,直到 right 指针到达数组末尾。
- 示例图示(以简单数组为例):
假设我们有数组 [1, 2, 1, 3] ,我们来演示一下整个过程。
- 初始时, left = 0 , right = 0 ,字典 count_dict 为空。
- 当 right = 0 时,子数组为 [1] ,权值为 1 ,记录下权值为 1 的子数组数量加 1 。
- 移动 right 指针,当 right = 1 时,子数组为 [1, 2] ,权值为 2 ,记录下权值为 2 的子数组数量加 1 。
- 继续移动 right 指针,当 right = 2 时,子数组为 [1, 2, 1] ,此时字典中记录的元素为 {1: 2, 2: 1} ,权值仍然为 2 ,继续移动 right 指针。
- 当 right = 3 时,子数组为 [1, 2, 1, 3] ,字典中记录的元素为 {1: 2, 2: 1, 3: 1} ,权值为 3 ,记录下权值为 3 的子数组数量加 1 。
然后通过收缩 left 指针,再次寻找满足不同权值的子数组,比如当 left = 1 , right = 3 时,子数组为 [2, 1, 3] ,权值为 3 ,又可以记录下权值为 3 的子数组数量加 1 ,以此类推,直到遍历完整个数组。
Python代码如下:
from typing import List def count_subarrays(nums: List[int]) -> List[int]: n = len(nums) result = [0] * n for left in range(n): count_dict = {} right = left while right < n: if nums[right] in count_dict: count_dict[nums[right]] += 1 else: count_dict[nums[right]] = 1 weight = len(count_dict) result[weight - 1] += 1 right += 1 return result
代码详解:
- count_subarrays 函数接受一个整数列表 nums 作为参数,并返回一个长度为 n 的列表 result ,其中 n 是输入数组 nums 的长度。这个返回的列表 result 就是我们要统计的权值分别为 1, 2, 3, …, n 的子数组数量。
- 首先,我们初始化 result 为一个长度为 n 的全零列表,用于存储每个权值对应的子数组数量。
- 然后,我们使用一个外层循环,通过遍历 left 指针从 0 到 n - 1 ,来考虑以每个元素作为子数组起始位置的情况。
- 对于每个 left 的值,我们在内层循环中初始化一个空字典 count_dict ,用于记录子数组中出现的元素及其出现次数。同时,我们将 right 指针也初始化为 left ,表示从当前 left 位置开始的子数组。
- 在内部循环中,我们不断移动 right 指针来扩大子数组。每次移动 right 指针时,我们检查当前元素 nums[right] 是否已经在 count_dict 中。如果在,就将其对应的计数加 1 ;如果不在,就将其添加到 count_dict 中,并将计数设为 1
- 然后,我们通过计算 count_dict 的长度来得到当前子数组的权值 weight 。由于列表索引是从 0 开始的,所以我们将 weight - 1 作为索引,将 result 中对应的元素加 1 ,表示找到了一个权值为 weight 的子数组。
- 最后,当 right 指针遍历完整个数组后,我们就得到了所有以当前 left 位置开始的子数组的权值情况。外层循环继续移动 left 指针,重复上述过程,直到考虑完所有可能的子数组起始位置。
- 最终,函数返回 result 列表,其中第 i 个元素就表示权值为 i + 1 的子数组数量。