数据结构 - 差分数组 Difference Array

在算法问题中,如何高效处理数组区间的修改操作是一个常见且重要的话题。比如:

  • 需要在一个数组的多个区间上进行加减操作,最终输出结果;
  • 频繁调整数组部分区间的值,但需要快速恢复整体状态;
  • 处理二维平面或更高维数据的区域更新问题。

通常,我们可以使用暴力遍历的方法,但当数组规模较大、操作次数较多时,暴力方法的效率会迅速成为瓶颈。这时,我们就需要一种能够在常数时间内完成区间修改的高效工具——差分数组

差分数组是一种借助“记录变化”而非直接修改原数组的巧妙方法。通过它,我们不仅可以快速处理区间修改,还可以在多次操作后迅速恢复最终的数组状态。本文将从基础概念出发,带你深入了解差分数组的工作原理、代码实现及其应用场景。

1. 什么是差分数组?

给定一个数组 \(a\),我们可以通过一个差分数组 \(diff\) 来表示 \(a\) 的变化:

  • 定义 \(diff[i] = a[i] - a[i-1]\),(假设\(diff[0] = a[0]\));
  • 由此,我们可以反推原数组:\(a[i] = a[i-1] + diff[i]\)

2. 差分数组的基本操作

2.1 区间加值操作

假设我们希望再数组 \(a\) 的区间 \([l,r]\) 中所有元素都加上一个值 \(v\),差分数组的做法是:

diff[l] += v;
diff[r+1] -= v;

通过这样的操作,区间 \([l, r]\) 中的每个元素都会加上 \(v\)。因为

\[\begin{align*} a[x] = a[x-1]+ diff[x] = a[l-1] + \sum_{l \leq i \leq x} diff[i], \quad (l \leq x \leq r). \end{align*} \]

在还原数组时,区间 \([l, r]\) 中的每个元素都会加上 \(diff[l]\),因此每个元素都会加上值 \(v\);而下标大于 $r $ 的元素不希望加上值 \(v\),因此令 \(diff[r+1]\) 自减即可。

2.2 数组还原操作

在完成多次区间操作后,我们通过前缀和的方式还原原始数组:

a[0] = diff[0];
a[i] = a[i-1] + diff[i];

3. 差分数组的复杂度分析

  • 时间复杂度:\(O(n+q)\),其中 \(n\) 是数组长度,\(q\) 是区间修改的操作次数。
  • 空间复杂度:\(O(n)\)

4. 实例

3355. 零数组变换 I - 力扣(LeetCode)

3356. 零数组变换 II - 力扣(LeetCode)

posted @ 2025-02-24 15:07  木杉的园子  阅读(153)  评论(0)    收藏  举报