题目解析 小B的极差之和 | 豆包MarsCode AI刷题

104 阅读5分钟

问题描述

小B拥有一个数组 a,她使用这个数组构造了一个新数组 b。其中,a[i] 表示在新数组 b 中有 a[i] 个 i+1。例如,若 a = [2, 3, 1],那么新数组 b = [1, 1, 2, 2, 2, 3],因为 a[0] = 2 代表数组 b 中有 2 个 1a[1] = 3 代表数组 b 中有 3 个 2a[2] = 1 代表数组 b 中有 1 个 3

现在,你需要帮助小B求出 b 数组中所有连续子数组的极差之和。由于答案可能非常大,请对 109+7109+7 取模。

数组的极差定义为子数组的最大值减去最小值。


测试样例

样例1:

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

样例2:

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

样例3:

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

题目解析

题目描述
小B有一个数组 a,并根据数组 a 构造了一个新数组 b。数组 a[i] 表示在新数组 b 中,数字 i+1 出现 a[i] 次。我们需要求出 b 数组中所有连续子数组的极差之和。极差定义为子数组的最大值减去最小值。

例如,对于输入:

  • a = [2, 3, 1],构造的数组 b = [1, 1, 2, 2, 2, 3]
  • 求 b 数组所有连续子数组的极差之和。

解题思路

核心思想

  1. 构造数组 b:通过遍历数组 a,可以根据 a[i] 的值来构造数组 bb 中每个数字 i+1 出现 a[i] 次。
  2. 计算极差:对于 b 数组的每一个连续子数组,计算该子数组的极差,极差即为子数组的最大值减去最小值。
  3. 优化计算:直接计算所有子数组的极差会导致时间复杂度过高,特别是 b 数组的长度可能非常大。可以使用滑动窗口或其他优化算法来减少重复计算,提升效率。
  4. 取模处理:由于结果可能非常大,要求最终结果对 10^9 + 7 取模。

步骤:

  1. 构造数组 b
    a 数组出发,按照 a[i] 的值构建 b 数组,其中每个数字 i+1 出现 a[i] 次。
  2. 计算极差之和
    对于 b 中的每个连续子数组,维护当前子数组的最大值和最小值。每添加一个新的元素时,更新最大值和最小值,并计算极差。
  3. 累加结果
    每次计算出一个子数组的极差后,将其加入总和,最后对 10^9 + 7 取模。

优化策略:

  • 使用双指针或滑动窗口技术来避免重复计算,提高效率。
  • 通过动态更新子数组的最大值和最小值,减少不必要的重复比较。

代码实现

def solution(n: int, a: list) -> int:
    MOD = 10**9 + 7
    b = []
    for i in range(n):
        b.extend([i + 1] * a[i])
    
    total_diff_sum = 0
    for i in range(len(b)):
        max_val, min_val = b[i], b[i]
        for j in range(i, len(b)):
            max_val = max(max_val, b[j])
            min_val = min(min_val, b[j])
            total_diff_sum += max_val - min_val
            total_diff_sum %= MOD

    return total_diff_sum

if __name__ == '__main__':
    print(solution(2, [2, 1]) == 2)
    print(solution(3, [1, 2, 1]) == 6)
    print(solution(4, [2, 3, 1, 1]) == 26)

复杂度

  • 时间复杂度O(S^2) ,其中 S = sum(a),表示数组 b 的长度。
  • 空间复杂度O(S) ,主要来自于数组 b 的存储。

这个算法的时间复杂度比较高,对于输入数据较大的情况下,可能会变得效率低下。如果需要更高效的解法,可以考虑使用优化算法,如单调栈、动态规划、线段树等技术来减少计算子数组极差的复杂度。

知识总结

  1. 数组的构造与展开: 在构造数组 b 时,我们通过将每个 i+1 重复 a[i] 次来构建 b 数组。这种操作类似于将一个计数数组扩展成一个具体的数列。
  2. 极差的计算: 极差定义为子数组的最大值减去最小值。对于一个子数组,我们需要动态跟踪该子数组的最大值和最小值。
  3. 模运算: 因为结果可能非常大,所以最终结果需要对 10^9 + 7 进行取模运算,以避免溢出并符合题目的要求。
  4. 滑动窗口/双指针技术: 在处理极差计算时,可以利用滑动窗口来避免重复计算。例如,当我们从左到右逐渐扩展子数组时,利用前一个子数组的最大值和最小值来推导当前子数组的极差。

学习建议

  1. 熟悉基础数据结构
    对于数组和子数组的处理要熟练,尤其是如何从一个计数数组构造出一个具体的数组。
  2. 掌握极差的概念
    极差(最大值 - 最小值)是许多算法中的常见问题,理解并掌握如何高效地计算极差是解题的关键。
  3. 练习优化算法
    直接枚举所有子数组的极差会导致高时间复杂度,因此需要学习如何优化算法。可以通过滑动窗口或动态更新的方法减少计算量。
  4. 熟悉模运算
    对于大数问题,模运算是必不可少的。要掌握模运算的基本技巧,尤其是如何在每步计算中进行模运算,防止结果溢出。