问题描述
小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 个 1,a[1] = 3 代表数组 b 中有 3 个 2,a[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数组所有连续子数组的极差之和。
解题思路
核心思想:
- 构造数组
b:通过遍历数组a,可以根据a[i]的值来构造数组b。b中每个数字i+1出现a[i]次。 - 计算极差:对于
b数组的每一个连续子数组,计算该子数组的极差,极差即为子数组的最大值减去最小值。 - 优化计算:直接计算所有子数组的极差会导致时间复杂度过高,特别是
b数组的长度可能非常大。可以使用滑动窗口或其他优化算法来减少重复计算,提升效率。 - 取模处理:由于结果可能非常大,要求最终结果对
10^9 + 7取模。
步骤:
- 构造数组
b:
从a数组出发,按照a[i]的值构建b数组,其中每个数字i+1出现a[i]次。 - 计算极差之和:
对于b中的每个连续子数组,维护当前子数组的最大值和最小值。每添加一个新的元素时,更新最大值和最小值,并计算极差。 - 累加结果:
每次计算出一个子数组的极差后,将其加入总和,最后对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的存储。
这个算法的时间复杂度比较高,对于输入数据较大的情况下,可能会变得效率低下。如果需要更高效的解法,可以考虑使用优化算法,如单调栈、动态规划、线段树等技术来减少计算子数组极差的复杂度。
知识总结
- 数组的构造与展开: 在构造数组
b时,我们通过将每个i+1重复a[i]次来构建b数组。这种操作类似于将一个计数数组扩展成一个具体的数列。 - 极差的计算: 极差定义为子数组的最大值减去最小值。对于一个子数组,我们需要动态跟踪该子数组的最大值和最小值。
- 模运算: 因为结果可能非常大,所以最终结果需要对
10^9 + 7进行取模运算,以避免溢出并符合题目的要求。 - 滑动窗口/双指针技术: 在处理极差计算时,可以利用滑动窗口来避免重复计算。例如,当我们从左到右逐渐扩展子数组时,利用前一个子数组的最大值和最小值来推导当前子数组的极差。
学习建议
- 熟悉基础数据结构:
对于数组和子数组的处理要熟练,尤其是如何从一个计数数组构造出一个具体的数组。 - 掌握极差的概念:
极差(最大值 - 最小值)是许多算法中的常见问题,理解并掌握如何高效地计算极差是解题的关键。 - 练习优化算法:
直接枚举所有子数组的极差会导致高时间复杂度,因此需要学习如何优化算法。可以通过滑动窗口或动态更新的方法减少计算量。 - 熟悉模运算:
对于大数问题,模运算是必不可少的。要掌握模运算的基本技巧,尤其是如何在每步计算中进行模运算,防止结果溢出。