← 目录 / 算法文档 · 模块五 区间处理技巧 / 5.2 差分

5.2 差分

前缀和负责"快速查询区间的和",差分负责反过来——"快速修改一整段区间"。

本页目录
① 为什么需要差分

上一节前缀和解决的是"原数组不变,反复查询某一段的和"——但如果反过来,题目要反复对数组做"给第 L 到第 R 个数都加上 v"这种操作呢?直接写循环,把区间里每个数都加一遍,单次操作要花 O(区间长度) 的时间——如果区间很长、操作次数又很多,照样会很慢。

差分就是用来解决这个问题的:它能把"给一整段区间加 v"这件事,变成只需要修改两个位置,时间复杂度直接降到 O(1)

② 差分数组的原理

差分数组 diff 记录的是相邻两个数之间的差距diff[i] = arr[i] - arr[i-1](约定 arr[0] = 0)。可以把原数组想象成一排台阶,每一级台阶相对上一级"升高了多少"或"降低了多少",正是 diff 数组存的内容。

用"台阶升降"理解差分:arr = {2, 2, 5, 5, 5, 3}
2
2
5
5
5
3
从第 1 级到第 2 级,高度没变(差距 0);从第 2 级到第 3 级,突然升高了 35-2=3);第 3、4 级之间没有变化;第 5 级到第 6 级,又降低了 23-5=-2)。diff 数组只关心"每一步升降了多少",不关心台阶的绝对高度——这正是它能高效处理"区间统一升降"的关键。
💡
差分和前缀和是一对"互逆"的操作:对原数组求差分,得到 diff 数组;反过来对 diff 数组求前缀和,正好能还原出原数组——diff[1]+diff[2]+...+diff[i] 算出来就是 arr[i]。这一点很重要:差分数组本身不是用来"看"的,它是一个中间工具,最终都要通过前缀和还原成真正的数组。
③ 用差分 O(1) 完成区间加法

现在看核心操作:给原数组第 L 到第 R 个数都加上 v,在差分数组上只需要两步:diff[L] += vdiff[R+1] -= v

用"台阶"来理解:从第 L 级开始,往后每一级都要比原来高 v——这件事只需要在第 L 级"垫高" vdiff[L] += v),后面的台阶因为是"接着上一级往上叠"的,会自动跟着一起抬高,不需要逐个去改;而第 R 级之后不应该再继续抬高了,所以要在第 R+1 级"退回去" vdiff[R+1] -= v),把多出来的高度抵消掉,让 R 之后的台阶恢复到原来的相对高度。

C++ · 差分数组实现区间加法
1void RangeAdd(int diff[], int l, int r, int v)
2{
3 diff[l] += v; // 从第l个数开始,整体抬高v
4 diff[r + 1] -= v; // 第r+1个数开始,把多出来的v退回去
5}

用一个长度 8、初始全是 0 的数组演示,依次做 3 次区间加法:

3 次区间加法操作 —— diff 数组的变化过程
初始 diff
0
0
0
0
0
0
0
0
区间[2,5]加3
0
3
0
0
0
-3
0
0
区间[4,7]加2
0
3
0
2
0
-3
0
-2
区间[1,3]加-1
-1
3
0
3
0
-3
0
-2
最终 diff
-1
3
0
3
0
-3
0
-2
还原后的数组
-1
2
2
5
5
2
2
0
每次操作都只动了 2 个位置(蓝色是 +v,粉色是 -v),不管区间多长,代价都一样。3 次操作做完之后,对 diff 数组求一次前缀和,就能直接还原出最终的数组 {-1,2,2,5,5,2,2,0}——和真的去逐个执行 3 次区间加法、暴力模拟出来的结果完全一致。
C++ · 还原最终数组(对 diff 求前缀和)
1int result[n + 1] = {0};
2for (int i = 1; i <= n; i++)
3{
4 result[i] = result[i - 1] + diff[i]; // 和5.1节求前缀和的写法完全一样
5}
④ 完整代码与对比

假设数组长度 n=1000,一共要做 1000 次区间加法操作(每次区间长度平均按 500 估算):

1000 次区间加法 —— 两种做法的总运算次数对比
每次直接修改区间
约 50 万次
差分(操作+还原)
约 3000 次
每次操作都直接把区间里的数逐个加一遍,1000 次操作、每次平均改 500 个数,总共约 50万 次;差分每次操作只改 2 个位置(1000×2=2000 次),最后再花一次 O(n) 还原出最终数组(1000 次),总共约 3000 次——快了 160 倍以上
做法单次区间加法q 次操作总复杂度
直接修改区间O(区间长度)O(n × q)(最坏情况)
差分O(1)O(n + q)
🎯
前缀和与差分正好是一对搭档:前缀和应对"数据不变、反复查询区间和",差分应对"反复做区间加法、最后统一查看结果"。如果题目既要频繁修改区间,又要随时查询任意区间的和(而不是等所有操作做完才查一次),这两个简单工具就都不够用了——需要用到模块十五的树状数组、线段树,它们能同时支持高效的区间修改和区间查询,是这一类问题的进阶解法。