变长子数组求和-LeetCode
3427. 变长子数组求和
🎯 问题描述
描述:
给你一个整数数组 nums。
对于数组中的每个元素 nums[i],我们需要计算一个特定子数组的和。
该子数组以 i 结尾,其起始位置由 nums[i] 的值决定。
具体来说,对于下标 i,子数组的起始下标为 start = max(0, i - nums[i])。
你需要返回所有这些子数组和的总和。
说明:
-
这是一个前缀和的应用题。
-
核心策略:
- 题目要求计算多个不同长度、不同起点的子数组和。
- 如果直接对每个位置都遍历求和,时间复杂度会达到 。
- 利用前缀和数组,我们可以在 的时间内计算任意区间的和,从而将总复杂度降为 。
-
逻辑定义:
- 对于每个
i,计算区间[max(0, i - nums[i]), i]的元素和。 - 最后将所有计算出的和累加。
- 对于每个
-
示例:
-
示例 1:
1 | 输入:nums = [2, 1, 3] |
💻 解题思路
思路1:前缀和 + 变长窗口
核心逻辑
- 构建前缀和数组
pre:pre[i+1]表示nums[0]到nums[i]的累加和。- 通过一次遍历即可完成构建。
- 注意:标准前缀和通常令
pre[0] = 0,这样pre[i+1]才是前i+1个元素的和。你的代码中pre[0]=nums[0]是一种变体,配合后续的减法逻辑使用。
- 计算变长子数组和:
- 遍历每个下标
i。 - 确定起点:
start = max(0, i - nums[i])。这意味着子数组的长度受限于当前元素的值。 - 利用前缀和求和:区间
[start, i]的和等于pre[i+1] - pre[start]。- 这里利用了前缀和的性质:。
- 遍历每个下标
- 累加结果:
- 将每个位置计算出的子数组和累加到最终结果中。
代码实现
1 | class Solution: |
📊 性能分析
- 时间复杂度:
- 构建前缀和数组:。
- 遍历计算每个位置的子数组和:。
- 每次查询区间和的时间是 。
- 总体线性时间,效率很高。
- 空间复杂度:
- 需要一个长度为 的
pre数组来存储前缀和。
- 需要一个长度为 的
思考
-
前缀和的初始化:
- 标准做法:
pre[0] = 0。这样pre[1]才是nums[0],pre[i+1]才是nums[0] + ... + nums[i]。 - 区间
[L, R]的和公式为pre[R+1] - pre[L]。
- 标准做法:
-
start = max(0, i - nums[i])的含义:- 这个公式定义了一个变长窗口。
- 窗口的长度大致为
nums[i] + 1(如果i >= nums[i])。 - 这通常出现在涉及“跳跃能力”或“影响范围”的题目中。
-
为什么使用前缀和?
- 如果不用前缀和,对于每个
i,我们都需要一个循环从start加到i。 - 最坏情况下(例如
nums[i]很大),每次求和需要 ,总复杂度变成 。 - 前缀和通过预处理,用空间换取了时间,将查询操作降为 。
- 如果不用前缀和,对于每个
-
空间优化:
- 虽然前缀和需要 空间,但如果我们只需要最终总和,其实不需要存储整个
pre数组。 - 不过,由于
start是跳变的(不是单调递增的滑动窗口),我们无法简单地用一个变量维护当前窗口和,因此保留前缀和数组是合理的。
- 虽然前缀和需要 空间,但如果我们只需要最终总和,其实不需要存储整个
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 笺札!






