--- comments: true difficulty: 中等 edit_url: https://github.com/doocs/leetcode/edit/main/solution/0300-0399/0370.Range%20Addition/README.md tags: - 数组 - 前缀和 --- # [370. 区间加法 🔒](https://leetcode.cn/problems/range-addition) [English Version](/solution/0300-0399/0370.Range%20Addition/README_EN.md) ## 题目描述

假设你有一个长度为 n 的数组,初始情况下所有的数字均为 0,你将会被给出 k​​​​​​ 个更新的操作。

其中,每个操作会被表示为一个三元组:[startIndex, endIndex, inc],你需要将子数组 A[startIndex ... endIndex](包括 startIndex 和 endIndex)增加 inc

请你返回 k 次操作后的数组。

示例:

输入: length = 5, updates = [[1,3,2],[2,4,3],[0,2,-2]]
输出: [-2,0,3,5,3]

解释:

初始状态:
[0,0,0,0,0]

进行了操作 [1,3,2] 后的状态:
[0,2,2,2,0]

进行了操作 [2,4,3] 后的状态:
[0,2,5,5,3]

进行了操作 [0,2,-2] 后的状态:
[-2,0,3,5,3]

 

提示:

## 解法 ### 方法一:差分数组 差分数组模板题。 我们定义 $d$ 为差分数组。给区间 $[l,..r]$ 中的每一个数加上 $c$,那么有 $d[l] += c$,并且 $d[r+1] -= c$。最后我们对差分数组求前缀和,即可得到原数组。 时间复杂度 $O(n)$,空间复杂度 $O(n)$。其中 $n$ 为数组长度。 #### Python3 ```python class Solution: def getModifiedArray(self, length: int, updates: List[List[int]]) -> List[int]: d = [0] * length for l, r, c in updates: d[l] += c if r + 1 < length: d[r + 1] -= c return list(accumulate(d)) ``` #### Java ```java class Solution { public int[] getModifiedArray(int length, int[][] updates) { int[] d = new int[length]; for (var e : updates) { int l = e[0], r = e[1], c = e[2]; d[l] += c; if (r + 1 < length) { d[r + 1] -= c; } } for (int i = 1; i < length; ++i) { d[i] += d[i - 1]; } return d; } } ``` #### C++ ```cpp class Solution { public: vector getModifiedArray(int length, vector>& updates) { vector d(length); for (const auto& e : updates) { int l = e[0], r = e[1], c = e[2]; d[l] += c; if (r + 1 < length) { d[r + 1] -= c; } } for (int i = 1; i < length; ++i) { d[i] += d[i - 1]; } return d; } }; ``` #### Go ```go func getModifiedArray(length int, updates [][]int) []int { d := make([]int, length) for _, e := range updates { l, r, c := e[0], e[1], e[2] d[l] += c if r+1 < length { d[r+1] -= c } } for i := 1; i < length; i++ { d[i] += d[i-1] } return d } ``` #### TypeScript ```ts function getModifiedArray(length: number, updates: number[][]): number[] { const d: number[] = Array(length).fill(0); for (const [l, r, c] of updates) { d[l] += c; if (r + 1 < length) { d[r + 1] -= c; } } for (let i = 1; i < length; ++i) { d[i] += d[i - 1]; } return d; } ``` #### JavaScript ```js /** * @param {number} length * @param {number[][]} updates * @return {number[]} */ var getModifiedArray = function (length, updates) { const d = Array(length).fill(0); for (const [l, r, c] of updates) { d[l] += c; if (r + 1 < length) { d[r + 1] -= c; } } for (let i = 1; i < length; ++i) { d[i] += d[i - 1]; } return d; }; ``` ### 方法二:树状数组 + 差分思想 时间复杂度 $O(n\times \log n)$。 树状数组,也称作“二叉索引树”(Binary Indexed Tree)或 Fenwick 树。 它可以高效地实现如下两个操作: 1. **单点更新** `update(x, delta)`: 把序列 $x$ 位置的数加上一个值 $delta$; 1. **前缀和查询** `query(x)`:查询序列 $[1,...x]$ 区间的区间和,即位置 $x$ 的前缀和。 这两个操作的时间复杂度均为 $O(\log n)$。 #### Python3 ```python class BinaryIndexedTree: __slots__ = "n", "c" def __init__(self, n: int): self.n = n self.c = [0] * (n + 1) def update(self, x: int, delta: int) -> None: while x <= self.n: self.c[x] += delta x += x & -x def query(self, x: int) -> int: s = 0 while x: s += self.c[x] x -= x & -x return s class Solution: def getModifiedArray(self, length: int, updates: List[List[int]]) -> List[int]: tree = BinaryIndexedTree(length) for l, r, c in updates: tree.update(l + 1, c) tree.update(r + 2, -c) return [tree.query(i + 1) for i in range(length)] ``` #### Java ```java class BinaryIndexedTree { private int n; private int[] c; public BinaryIndexedTree(int n) { this.n = n; this.c = new int[n + 1]; } public void update(int x, int delta) { for (; x <= n; x += x & -x) { c[x] += delta; } } public int query(int x) { int s = 0; for (; x > 0; x -= x & -x) { s += c[x]; } return s; } } class Solution { public int[] getModifiedArray(int length, int[][] updates) { var tree = new BinaryIndexedTree(length); for (var e : updates) { int l = e[0], r = e[1], c = e[2]; tree.update(l + 1, c); tree.update(r + 2, -c); } int[] ans = new int[length]; for (int i = 0; i < length; ++i) { ans[i] = tree.query(i + 1); } return ans; } } ``` #### C++ ```cpp class BinaryIndexedTree { private: int n; vector c; public: BinaryIndexedTree(int n) : n(n) , c(n + 1) {} void update(int x, int delta) { for (; x <= n; x += x & -x) { c[x] += delta; } } int query(int x) { int s = 0; for (; x > 0; x -= x & -x) { s += c[x]; } return s; } }; class Solution { public: vector getModifiedArray(int length, vector>& updates) { BinaryIndexedTree* tree = new BinaryIndexedTree(length); for (const auto& e : updates) { int l = e[0], r = e[1], c = e[2]; tree->update(l + 1, c); tree->update(r + 2, -c); } vector ans; for (int i = 0; i < length; ++i) { ans.push_back(tree->query(i + 1)); } return ans; } }; ``` #### Go ```go type BinaryIndexedTree struct { n int c []int } func NewBinaryIndexedTree(n int) *BinaryIndexedTree { return &BinaryIndexedTree{n: n, c: make([]int, n+1)} } func (bit *BinaryIndexedTree) update(x, delta int) { for ; x <= bit.n; x += x & -x { bit.c[x] += delta } } func (bit *BinaryIndexedTree) query(x int) int { s := 0 for ; x > 0; x -= x & -x { s += bit.c[x] } return s } func getModifiedArray(length int, updates [][]int) (ans []int) { bit := NewBinaryIndexedTree(length) for _, e := range updates { l, r, c := e[0], e[1], e[2] bit.update(l+1, c) bit.update(r+2, -c) } for i := 1; i <= length; i++ { ans = append(ans, bit.query(i)) } return } ``` #### TypeScript ```ts class BinaryIndexedTree { private n: number; private c: number[]; constructor(n: number) { this.n = n; this.c = Array(n + 1).fill(0); } update(x: number, delta: number): void { for (; x <= this.n; x += x & -x) { this.c[x] += delta; } } query(x: number): number { let s = 0; for (; x > 0; x -= x & -x) { s += this.c[x]; } return s; } } function getModifiedArray(length: number, updates: number[][]): number[] { const bit = new BinaryIndexedTree(length); for (const [l, r, c] of updates) { bit.update(l + 1, c); bit.update(r + 2, -c); } return Array.from({ length }, (_, i) => bit.query(i + 1)); } ``` #### JavaScript ```js /** * @param {number} length * @param {number[][]} updates * @return {number[]} */ var getModifiedArray = function (length, updates) { class BinaryIndexedTree { constructor(n) { this.n = n; this.c = Array(n + 1).fill(0); } update(x, delta) { while (x <= this.n) { this.c[x] += delta; x += x & -x; } } query(x) { let s = 0; while (x > 0) { s += this.c[x]; x -= x & -x; } return s; } } const bit = new BinaryIndexedTree(length); for (const [l, r, c] of updates) { bit.update(l + 1, c); bit.update(r + 2, -c); } return Array.from({ length }, (_, i) => bit.query(i + 1)); }; ```