小A的子数组权值 | 青训营刷题

52 阅读3分钟

问题描述

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

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

做题思路:

  1. 暴力枚举所有子数组

    • 我们需要找出数组 a 中权值(即子数组内不同元素的个数)为从 1 到 n 的子数组数量。为了实现这个目标,一种直观的方法是通过两层循环来枚举所有可能的连续子数组。
    • 外层循环控制子数组的起始位置 i,从数组的开头开始,逐步向后移动,直到数组的倒数第二个位置(因为内层循环还会从 i 往后延伸形成子数组)。
    • 内层循环控制子数组的结束位置 j,从外层循环确定的起始位置 i 开始,一直到数组的末尾,这样就可以枚举出以 i 为起始位置的所有连续子数组。
  2. 统计子数组内不同元素个数

    • 对于每一个枚举出来的子数组(由 i 和 j 确定),我们需要统计其中不同元素的个数,也就是子数组的权值。
    • 这里使用一个无序映射(unordered_map)来实现。在每次内层循环迭代时,对于当前元素 a[j],我们检查它在映射 count 中的出现次数。
    • 如果 count[a[j]] 等于 0,说明这个元素是第一次在当前子数组中出现,那么就将不同元素的个数 distinct 加 1。然后,无论是否是第一次出现,都要将该元素在映射中的出现次数加 1,以记录它在子数组中的出现情况。
  3. 记录权值对应的子数组数量

    • 在统计完每个子数组的不同元素个数(即权值)后,我们使用一个数组 c 来记录权值为不同值时的子数组数量。
    • 数组 c 的下标表示权值,数组元素的值表示权值为该下标的子数组数量。所以,每当我们确定了一个子数组的权值 distinct 后,就将 c[distinct] 的值加 1
vector<int> solution(int n, vector<int>& a) {
    vector<int> c(n + 1, 0);
    for (int i = 0; i < n; ++i) {
        unordered_map<int, int> count;
        int distinct = 0;
        for (int j = i; j < n; ++j) {
            if (count[a[j]] == 0) {
                distinct++;
            }
            count[a[j]]++;
            c[distinct]++;
        }
    }
    return vector<int>(c.begin() + 1, c.end());
}

在这段代码中,通过两层循环枚举了所有可能的连续子数组,并借助无序映射统计了每个子数组内不同元素的个数,最后将不同权值对应的子数组数量记录在数组 c 中并返回。整体时间复杂度相对较高,因为是通过暴力枚举的方式,大致为 ,其中 n 是数组 a 的长度。空间复杂度主要取决于无序映射 count 存储的不同元素的数量,在最坏情况下可能达到 。