小A的子数组权值 | 豆包MarsCode AI刷题

107 阅读4分钟

一、小A的子数组权值

问题描述

小A拿到了一个长度为nn的数组,并且定义了一个连续子数组的“权值”为该子数组内不同元素的个数。现在,她想知道,权值分别为1,2,3,…,n1,2,3,…,n的子数组数量有多少个。

你需要根据给定的数组,输出一个包含nn个整数的数组,第ii个数表示权值为ii的子数组数量。

测试样例

样例1

输入:n = 4, a = [1, 2, 2, 3]
输出:[5, 4, 1, 0]

样例2

输入:n = 3, a = [1, 1, 1]
输出:[6, 0, 0]

样例3

输入:n = 5, a = [1, 2, 3, 2, 1]
输出:[5, 5, 5, 0, 0]

二、解题思路

(1)问题理解

题目要求我们计算一个长度为 n 的数组中,所有可能的连续子数组的权值,并统计每个权值的子数组数量。这里的“权值”定义为子数组中不同元素的个数。我们需要输出一个长度为 n 的数组,其中第 i 个元素表示权值为 i 的子数组数量。

(2)数据结构选择

1.集合(Set) :用于记录当前子数组中的不同元素。集合的特性是自动去重,因此可以方便地计算不同元素的个数。

2.数组(Array) :用于存储每个权值的子数组数量。数组的长度为 n+1,其中 c[i] 表示权值为 i 的子数组数量。

(3)算法步骤

1.初始化计数数组 c

创建一个长度为 n+1 的数组 c,所有元素初始化为0。这个数组用于记录每个权值的子数组数量。

2.双层循环遍历所有子数组

外层循环 i 从0到 n-1,表示子数组的起始位置。内层循环 j 从 i 到 n-1,表示子数组的结束位置。

3.使用集合 seen 记录当前子数组中的不同元素

每次将 a[j] 加入集合 seen。计算当前子数组的权值 weight,即集合 seen 的大小。如果 weight 小于等于 n,则将 c[weight] 加1。

4.返回结果

返回 c[1:],即权值为1到 n 的子数组数量。

三、完整代码

def solution(n: int, a: list) -> list:
    c = [0 for _ in range(n + 1)]
    
    # 遍历所有可能的子数组
    for i in range(n):
        seen = set()
        for j in range(i, n):
            seen.add(a[j])
            weight = len(seen)
            if weight <= n:
                c[weight] += 1
            else:
                break
    
    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])

四、对代码的分析

(1)初始化计数数组 c

我们创建一个长度为 n+1 的数组 c,所有元素初始化为0。这个数组用于记录每个权值的子数组数量。例如,c[1] 表示权值为1的子数组数量,c[2] 表示权值为2的子数组数量,依此类推。

(2)双层循环遍历所有子数组

外层循环 i 从0到 n-1,表示子数组的起始位置。对于每个起始位置 i,我们遍历从 i 到 n-1 的所有可能的结束位置 j

内层循环 j 从 i 到 n-1,表示子数组的结束位置。对于每个结束位置 j,我们计算从 i 到 j 的子数组的权值。

(3)使用集合 seen 记录当前子数组中的不同元素

在每次内层循环中,我们将 a[j] 加入集合 seen。集合的特性是自动去重,因此集合的大小就是当前子数组中不同元素的个数。 计算当前子数组的权值 weight,即集合 seen 的大小。 如果 weight 小于等于 n,则将 c[weight] 加1。这是因为我们只关心权值在1到 n 之间的子数组数量。

(4)返回结果

最后,我们返回 c[1:],即权值为1到 n 的子数组数量。这是因为题目要求我们输出一个长度为 n 的数组,其中第 i 个元素表示权值为 i 的子数组数量。

五、复杂度分析

时间复杂度:双层循环的时间复杂度为 O(n^2),其中 n 是数组的长度。对于每个子数组,我们使用集合来计算不同元素的个数,集合操作的时间复杂度为 O(1)。因此,总的时间复杂度为 O(n^2)

空间复杂度:我们使用了一个长度为 n+1 的数组 c 和一个集合 seen,因此空间复杂度为 O(n)

六、总结

通过使用双层循环和集合来遍历所有可能的子数组,并统计每个子数组的权值,我们可以高效地计算出每个权值的子数组数量。这种方法的时间复杂度为 O(n^2),空间复杂度为 O(n),适用于大多数情况。