刷题笔记:小B的极差之和 | 豆包MarsCode AI刷题

71 阅读4分钟

问题描述

给定一个数组 a,你需要构造一个数组 b,数组 b 的构造规则是:对于数组 a 中的每个元素 a[i],它在 b 中表示有 a[i] 个元素 i+1。构造完成后,要求计算数组 b 中所有连续子数组的极差之和,其中极差定义为子数组的最大值减去最小值。

最终返回的结果需要对 10^9 + 7 取模。


问题剖析

  1. 数组 b 的构造

    • 数组 b 由数组 a 构造而成,其中每个元素 i 的值 a[i] 表示 b 中有 a[i] 个值为 i+1 的元素。因此数组 b 是由连续的相同元素构成的,这一点非常重要。
  2. 极差计算

    • 极差是指子数组中的最大值减去最小值。
    • 给定数组 b,需要计算所有连续子数组的极差之和。
  3. 子数组计算

    • 数组的所有子数组数目是 O(m^2),其中 m 是数组 b 的长度。对每一个子数组,我们都需要计算其极差,直接计算会导致较高的时间复杂度。
  4. 问题约束

    • 输出的结果可能非常大,需要对 10^9 + 7 取模。
    • 数组 a 中的值较小,构造出的数组 b 会是较长的数组,这意味着我们必须对计算方式进行优化。

解题思路

  1. 数组 b 的构造

    • 数组 b 的构造是直接的。对于每个 a[i],我们需要在 b 中放入 a[i]i+1
  2. 极差计算

    • 由于数组 b 中的每个数字都是连续的相同值,可以通过滑动窗口的方式减少计算量。对于每个元素 x,我们可以计算该元素在子数组中的极差贡献。
    • 可以通过两层循环遍历所有的子数组,计算每个子数组的最大值和最小值,然后累加极差。
  3. 优化

    • 通过直接遍历和更新最小值与最大值,而不是为每个子数组重复计算,可以在一定程度上减少计算的复杂度。
  4. 取模操作

    • 因为极差之和可能会很大,所以每次累加时都要对 109+710^9 + 7109+7 取模,避免数值溢出。
  5. 复杂度分析

    • 假设 b 的长度为 m,构造 b 的时间复杂度是 O(n),其中 n 是数组 a 的长度。
    • 遍历所有子数组的时间复杂度是 O(m^2),因为对于每一个 b 的子数组,计算极差需要 O(1) 时间。

解题代码

python
复制代码
def solution(n: int, a: list) -> int:
    MOD = 10**9 + 7
    
    # Step 1: Build the array b
    b = []
    for i in range(n):
        b.extend([i + 1] * a[i])
    
    # Step 2: Calculate the sum of range differences of all subarrays of b
    total_sum = 0
    length_b = len(b)
    
    # For each possible subarray
    for i in range(length_b):
        current_min = current_max = b[i]
        
        # Extend the subarray by including elements from i to j
        for j in range(i, length_b):
            current_min = min(current_min, b[j])
            current_max = max(current_max, b[j])
            total_sum += (current_max - current_min)
            total_sum %= MOD  # Keep the result within the modulo
    
    return total_sum


代码剖析

  1. 数组 b 的构造

    • 使用 b.extend([i + 1] * a[i]) 来构造数组 b。对于数组 a 中的每个元素 a[i],我们将 i+1 添加到 ba[i] 次。
  2. 计算极差

    • 使用两层循环遍历所有子数组。外层循环从每个元素开始,内层循环扩展子数组,更新当前子数组的最小值和最大值。
    • current_mincurrent_max 分别记录当前子数组的最小值和最大值。
    • 对每个子数组的极差 current_max - current_min 进行累加,并取模 10^9 + 7 保持结果在合理范围内。
  3. 时间复杂度

    • 对于数组 b,我们有 O(m^2)的时间复杂度,其中 m 是数组 b 的长度(即所有 a[i] 的总和)。
    • 通过两层循环来遍历子数组和计算极差。

总结思考

  1. 数组构造的巧妙性

    • 数组 b 的构造是题目关键之一,通过数组 a 中的每个元素来确定 b 中的值,可以保证数组 b 中的元素有连续重复的特性。这使得极差计算的处理可以通过滑动窗口来优化。
  2. 极差计算的复杂性

    • 直接计算每个子数组的极差是高复杂度的,但通过两层循环遍历并逐步更新最小值和最大值,我们避免了重复计算,提高了效率。
  3. 对大数据量的处理

    • 题目中没有明确给出数据的大小,但极差计算的时间复杂度 O(m^2) 会导致在数据较大时超时。可以考虑更进一步的优化,比如使用单调栈来加速最大值和最小值的查询,或者通过动态规划来减少重复计算。
  4. 模块化思想

    • 对于大数运算,确保在每次累加时进行取模操作是非常重要的。

通过以上思路和实现,可以高效地解决数组子数组极差之和的问题,理解了数组构造、极差计算、以及如何通过优化减少时间复杂度。