148.小A的子数组权值
问题描述
小A拿到了一个长度为nn的数组,并且定义了一个连续子数组的“权值”为该子数组内不同元素的个数。现在,她想知道,权值分别为1,2,3,…,n1,2,3,…,n的子数组数量有多少个。
思路解析
-
整体思路方向:
要解决的问题是统计给定长度为n的数组a中,权值(连续子数组内不同元素的个数)分别为 1 到n的子数组数量。整体思路是通过两层循环遍历出所有可能的连续子数组,在遍历每个子数组的过程中,实时统计其中不同元素的个数(也就是权值),并相应地更新对应权值的子数组数量统计结果。 -
各环节思路:
- 1.初始化统计列表环节:
创建一个长度为n + 1的列表c,并初始化为全 0。这个列表的作用是用于记录权值从 0 到n的子数组数量,索引对应权值,后续在遍历子数组过程中,根据计算出的子数组权值来更新对应索引位置上的值,不过最后返回结果时只需要返回索引 1 到n对应的部分(因为权值为 0 的情况不符合题意要求)。 - 2.子数组遍历与元素统计环节:
通过两层嵌套的for循环来生成所有可能的连续子数组。外层循环以变量i控制子数组的起始位置,从 0 到n - 1进行遍历;内层循环以变量j控制子数组的结束位置,从外层循环确定的起始位置i开始,一直到n - 1进行遍历,这样a[i:j + 1]就能表示出每一个连续子数组了。
在遍历每个子数组(也就是内层循环每次执行时)的过程中,使用一个字典count_dict来记录当前子数组中每个元素出现的次数。每当遇到一个元素a[j],先判断它是否已经在字典count_dict中,如果在,就将其对应出现次数加 1;如果不在,说明是新出现的不同元素,将其加入字典且出现次数记为 1,同时把记录不同元素个数的变量distinct_count加 1,以此实时统计出当前子数组内不同元素的个数(即权值)。 - 3.权值对应数量更新环节:
在计算出当前子数组的权值distinct_count后,判断如果它小于等于n,就将统计列表c中索引为distinct_count的元素值加 1,表示权值为distinct_count的子数组数量又多了一个。 - 4.返回结果环节:
最后返回统计列表c中索引从 1 到n的切片部分,也就是只返回符合题意要求的权值为 1 到n的子数组数量统计结果。
- 1.初始化统计列表环节:
解题步骤
1.函数定义与初始化统计列表:
定义了一个名为 solution 的函数,它接收两个参数,一个是整数 n,表示数组的长度;另一个是列表 a,代表给定的数组。在函数内部,首先创建了一个长度为 n + 1 的列表 c,并使用列表推导式初始化为全 0,这个列表将用于后续统计不同权值的子数组数量,其索引对应权值(例如 c[2] 用于统计权值为 2 的子数组数量)。
2.两层循环遍历子数组并统计元素出现次数与权值:
-
外层循环:
使用for循环,让变量i从 0 到n - 1遍历,它控制了子数组的起始位置。每次外层循环开始,都会初始化一个空字典count_dict,用于记录当前从位置i开始的子数组中各元素出现次数,同时将记录不同元素个数的变量distinct_count初始化为 0。 -
内层循环:
在内层的for循环中,变量j从外层循环确定的起始位置i开始,到n - 1进行遍历,它确定了子数组的结束位置,这样就能通过切片a[i:j + 1]得到每一个连续子数组了。对于当前子数组中的每个元素a[j]:- 首先通过
if a[j] in count_dict判断它是否已经在字典count_dict中,如果在,就执行count_dict[a[j]] += 1,也就是将该元素在当前子数组中的出现次数加 1;如果不在字典中,说明这是一个新出现的不同元素,执行count_dict[a[j]] = 1将其加入字典且出现次数记为 1,同时执行distinct_count += 1,将记录不同元素个数的变量distinct_count加 1,这样就能实时统计出当前子数组内不同元素的个数(即权值)了。 - 然后通过
if distinct_count <= n判断当前子数组的权值distinct_count是否小于等于n,如果是,就执行c[distinct_count] += 1,将统计列表c中对应索引(也就是权值对应的位置)的元素值加 1,表示权值为distinct_count的子数组数量又多了一个。
- 首先通过
复杂度分析
-
时间复杂度: 代码通过两层嵌套循环生成子数组,外层循环执行
n次,内层循环最多执行n次,共O(n^2)次循环操作来生成子数组,后续计算子数组权值及统计操作复杂度相对较低,整体时间复杂度由循环主导,为O(n^2)。 -
空间复杂度: 定义了长度为
n + 1的result列表用于统计,空间复杂度是O(n),循环中临时变量及临时集合占用空间相对固定,可忽略不计,所以整体空间复杂度为O(n)。
Code
def solution(n: int, a: list) -> list:
c = [0 for _ in range(n + 1)]
# 遍历所有可能的子数组
for i in range(n):
# 使用字典记录当前子数组中每个元素的出现次数
count_dict = {}
distinct_count = 0
for j in range(i, n):
# 更新当前元素的出现次数
if a[j] in count_dict:
count_dict[a[j]] += 1
else:
count_dict[a[j]] = 1
distinct_count += 1
# 更新权值为distinct_count的子数组数量
if distinct_count <= n:
c[distinct_count] += 1
return c[1:]
if __name__ == '__main__':
print(solution(4, [1, 2, 2, 3]) == [5, 4, 1, 0])
print(solution(3, [1, 1, 1]) == [6, 0, 0])
print(solution(5, [1, 2, 3, 2, 1]) == [5, 5, 5, 0, 0])