题目描述

✅ 1480. 一维数组的动态和

image-20260929084834768

题意分析

返回一个与输入等长的数组,其中第 i 项等于原数组从下标零到 i 的全部元素之和。每个位置都需要一个累加结果,不是只返回整条数组的总和。

当前位置自己的值也包含在和中,第零项的结果就是原来的第零项。输入可能有负数,前缀和因此不一定递增,但累加规则不变。下面的实现直接把结果写回输入数组。

解法:原地前缀和

核心思路

[!blue]

相邻两个前缀只差一个元素:到位置 i 的总和,等于到位置 i - 1 的总和再加上当前位置的原值。因此已经计算过的前缀不必重新求和,可以从左到右逐个延长。

原地处理时保持一个明确状态:位置 i 左侧都已经保存对应的前缀和,而从 i 开始的部分仍然保留原值。所以执行 nums[i] += nums[i - 1] 时,读到的两项恰好分别是当前原值和前一个完整前缀,结果就是当前所需的前缀和。

覆盖当前位置不会破坏后续计算。以后的步骤只需要这里已经累计好的总和,不再需要它单独的旧值;右边尚未处理的原值也完全没动。因此不需要另外创建结果数组或保存所有旧值。

第零项已经是自身的前缀和,从下标一开始即可。每次更新后,已完成的前缀又延长一项,遍历结束时整个数组都变成所需结果,直接返回原数组。

解题步骤

  1. 保持第零个元素不变,它已经是第一个前缀的和。
  2. 从下标一到末尾依次处理,把上一位置已经算出的前缀和加到当前位置。
  3. 扫描结束后返回原数组,其所有位置均已保存前缀累加结果。

代码实现

class Solution {
    public int[] runningSum(int[] nums) {
        // 从 1 开始:nums[0] 的前缀和就是它自己,无需处理,也避免访问 nums[-1]。
        for (int i = 1; i < nums.length; i++) {
            // nums[i-1] 已是前缀和,nums[i] 还是原值,相加即得新前缀和。
            nums[i] += nums[i - 1];
        }

        return nums;
    }
}
func runningSum(nums []int) []int {
    // 从 1 开始:nums[0] 的前缀和就是它自己,无需处理,也避免访问 nums[-1]。
    for i := 1; i < len(nums); i++ {
        // nums[i-1] 已是前缀和,nums[i] 还是原值,相加即得新前缀和。
        nums[i] += nums[i-1]
    }

    return nums
}

复杂度分析

  • 时间复杂度:O(n)。除首项外,每个位置只进行一次加法。
  • 空间复杂度:O(1)。原地保存输出,只使用循环下标,不分配新的结果数组。

关键点总结

[!green]

  • 前缀递推复用前一个总和,避免每个位置都重新从头累加。
  • 左侧是已处理总和,当前位置仍是原值,遍历方向保证二者含义正确。
  • 负数不破坏递推关系,只会使前缀和可能增大也可能减小。
  • 返回值复用输入数组,输入内容会被改变。

易错点总结

[!yellow]

  • 从右向左更新:左侧尚未成为前缀和,只会得到部分相邻原值之和。
  • 从下标零开始读取 i - 1:会访问不存在的位置,应从一开始。
  • 每个位置都从头再次求和:大量重复计算会把线性处理变为平方量级。
  • 只返回最后的总和:题目需要每个前缀的结果,必须保留完整数组。
  • 假设输入数组仍保留原值:该实现覆盖输入,后续使用者拿到的已经是前缀和。

相似题目

题目 难度 关联与区别
303. 区域和检索 - 数组不可变 简单 动态和就是区间查询的前缀预处理结果,原题之后还用两前缀之差回答查询。
1732. 找到最高海拔 简单 原题只需要累计值的最大值,所以可滚动保存;本题要返回每个前缀结果。
转载与许可
作者
链接 https://hgnulb.github.io/blog/2022/39097833
许可 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!