每日大赛冷门技巧之后,这条知识点很多人不知道更少走弯路终于解释清楚了:建议反复看(有图)

引子 在各种每日大赛、刷题赛和面试题里,经常会遇到“对一段区间做大量更新,再查询最终结果”这种题型。直接逐项更新会超时或写起来很繁琐。有个看似简单但能把复杂度从 O(n·m) 降到 O(n+m) 的技巧——差分数组(Difference Array / 差分思想)——很多人知道名字但没弄清楚细节和常见变种。本文把原理、示例、易错点和进阶扩展一次讲清楚,配图和代码,建议至少过目两遍,遇到区间更新题立刻用起来。
核心思想(一句话) 把多次区间加/减的操作转化为对“差分数组”少量位置的修改,最后通过前缀和还原出最终数组。
为什么这样能快 对原数组 arr 做 [l, r] 区间加上值 x,直接逐个加需要触及 r-l+1 个元素;用差分只需对差分数组 diff 的两个位置做修改,然后一次性用前缀和还原出最终结果。多次操作合并后只需一次 O(n) 的还原。
差分数组原理(图示) 假设原数组 A = [a0, a1, a2, a3, a4]。定义差分数组 D 为: D[0] = A[0] D[i] = A[i] - A[i-1] (i >= 1)
示意图(在你的网站可用作图片)
- 图1:原数组与差分数组的对应关系(用箭头标注)
- 图2:对区间 [l, r] 加 x,在差分数组中只修改 D[l] += x,D[r+1] -= x(若 r+1 存在)
- 图3:对多个区间操作后,通过对 D 做前缀和还原得到最终 A
举个具体数字例子 原数组 A = [2, 5, 3, 8, 1] 对应差分 D = [2, 3, -2, 5, -7] (计算方式见上)
现在对区间 [1, 3](下标从 0 开始)每项加 4: 在差分上执行: D[1] += 4 -> 7 D[4] -= 4 -> -11
新的 D = [2, 7, -2, 5, -11] 还原 A' 为 D 的前缀和: A'[0]=2 A'[1]=2+7=9 A'[2]=9+(-2)=7 A'[3]=7+5=12 A'[4]=12+(-11)=1
得到 A' = [2,9,7,12,1],与直接修改一致,但只做了两个常数次修改 + 一次线性还原。
代码实现(Python) 下面是最常见的情形:初始数组已知,做 m 次区间加操作,最后输出最终数组。
def applyrangeupdates(arr, updates): n = len(arr) diff = [0] * (n + 1) # 多一个位置以方便处理 r+1 # 初始化差分 diff[0] = arr[0] for i in range(1, n): diff[i] = arr[i] - arr[i-1] # 处理每次更新,更新是 (l, r, x) for l, r, x in updates: diff[l] += x diff[r+1] -= x # r+1 在 n 范围内才做 # 还原 res = [0] * n cur = 0 for i in range(n): cur += diff[i] res[i] = cur return res
注意:上面 diff 长度为 n+1,保证 r+1 不越界;若 r = n-1,diff[n] 会被修改但不会在还原中使用,从而正确处理边界。
常见问题与易错点
- 边界处理:对 r = n-1 的更新不能直接 diff[r+1] 在长度为 n 的数组上访问越界,通常把 diff 长度设为 n+1 或在更新前判断 r+1 < n。
- 初始差分构造:有些人把 diff 全置零,然后对每个更新做 diff[l] += x / diff[r+1] -= x,但如果题目需要“在初始数组基础上”更新,记得先基于初始数组构造差分,否则会漏掉初始值。
- 需要点查询还是区间查询:差分适合批量区间更新、最终点值查询或最后整体输出。如果要求中间每次更新后即时查询某区间和,考虑用树状数组或线段树。
- 不是万能的:差分处理的是“加/减”类的线性操作。若要求区间乘、区间赋值(覆盖),单纯差分不够,要用懒标记线段树或更复杂的数据结构。
- 数据类型溢出:累加次数多时注意使用足够大的整型(例如 Python 默认不限,但 C++/Java 需要 long long)。
进阶变种(遇到这些再想优化)
- 多次查询混合:如果既有区间更新又要频繁查询区间和,可以把差分思想和前缀和结合,但更通用的是用树状数组(Fenwick Tree)或线段树支持在线更新与查询。
- 二维差分:处理矩阵的矩形区域加法时,使用二维差分(在四个角做修改)可以把复杂度从 O(n·m·q) 降到 O(n·m + q)。
- 差分 + 离散化:当区间边界是大整数或稀疏时,先离散化坐标再用差分,节省空间。
典型题目(练手推荐)
- 任意给出若干区间加/减,输出最终数组(入门题)
- 矩阵上若干次矩形区域加值,输出最后矩阵(二维差分)
- 给定初始数组和大量区间加操作,并多次询问某一点的值(差分或树状数组) 可在 LeetCode / Codeforces / AtCoder 寻找相应练习题,例如相关的“range addition”或“difference array”题目。
总结(快速回顾)
- 场景:大量区间增加/减少,最终想要数组结果或点值。
- 技巧:用差分数组只在区间端点修改,最后用前缀和还原。
- 好处:将复杂度大幅降到线性,编码简单且稳定。
- 别忘了边界 r+1 的处理和初始差分的构造。
配图建议(你的网站可以直接放)
- 图1:原数组到差分数组的映射(箭头 + 公式)
- 图2:一次区间更新在差分数组上的两个修改(示例 l, r, x)
- 图3:多个更新合并后的差分再前缀和还原成最终数组(一步步演示数值变化) 这些图能让读者更直观理解差分的“只改两处、最后一次还原”的核心优势。
如果你希望,我可以把上面的示例图做成可直接下载的 PNG,或者把 Python 代码改成 C++/Java 版本,甚至把几个练习题和标准答案放一起,方便你直接发布到网站上。你想先要哪一个补充?

最新留言