当前位置: 首页 > news >正文

差分数组(Difference Array)

差分数组(Difference Array)是一种用于高效处理数组区间增量操作的数据结构或技巧。它的核心思想是将原始数组的区间修改操作转换为差分数组的端点修改操作,从而将时间复杂度从 O(n) 降低到 O(1)。

核心概念

  1. 差分数组 diff的定义:​

    • 给定一个原始数组 arr,长度为 n

    • 差分数组 diff的长度也为 n

    • diff[0] = arr[0](第一个元素)

    • 对于 i >= 1diff[i] = arr[i] - arr[i - 1](当前元素减去前一个元素)

    原始数组 arr: [a0, a1, a2, a3, ..., a{n-1}]
    差分数组 diff:diff[0] = a0diff[1] = a1 - a0diff[2] = a2 - a1...diff[i] = a{i} - a{i-1}...diff[n-1] = a{n-1} - a{n-2}
  2. 从差分数组还原原始数组:​

    • 差分数组 diff存储了相邻元素的差值。

    • 通过对 diff数组求前缀和,可以还原出原始数组 arr

      • arr[0] = diff[0]

      • arr[1] = diff[0] + diff[1]

      • arr[2] = diff[0] + diff[1] + diff[2]

      • ...

      • arr[i] = diff[0] + diff[1] + ... + diff[i] = arr[i-1] + diff[i](对于 i >= 1

    arr[0] = diff[0]
    arr[1] = diff[0] + diff[1] = arr[0] + diff[1]
    arr[2] = diff[0] + diff[1] + diff[2] = arr[1] + diff[2]
    ...
    arr[i] = arr[i-1] + diff[i]

为什么有用?区间修改操作

差分数组最大的威力在于处理对原始数组某个区间内所有元素同时加上(或减去)一个常数 k​ 的操作。

  • 原始方法:​​ 如果要给 arr的区间 [l, r](包含 lr)的每个元素都加上 k,需要遍历该区间内的所有元素(lr),时间复杂度为 ​O(n)​​(n 是区间长度)。

  • 差分数组方法:​​ 只需要修改差分数组 diff两个元素​:

    1. diff[l] += k

    2. if (r + 1 < n) diff[r + 1] -= k(如果 r + 1没有超出数组边界)

原理:​

  1. 修改 diff[l] += k:根据还原公式 arr[i] = arr[i-1] + diff[i],这个操作会导致从位置 l开始,​之后所有位置arr[i]在计算时都额外加上了 k​(因为 diff[l]变大了 k,这个 k会传递到 arr[l], arr[l+1], arr[l+2], ...)。

  2. 修改 diff[r + 1] -= k(如果 r + 1 < n):这个操作是为了抵消掉区间 [r+1, n-1]上额外加上的 k。当还原到 arr[r+1]时,diff[r+1]减少了 k,使得 arr[r+1] = arr[r] + (diff[r+1] - k)。由于 arr[r]已经被加了 k(来自第一步的影响),arr[r+1]的计算变成了 (arr[r] + k) + (diff[r+1] - k) = arr[r] + diff[r+1],正好是原始值加上 diff[r+1],消除了 k的影响。之后的位置同理。

结果:​​ 只有区间 [l, r]内的元素在还原时被加上了 k,区间外的元素不受影响。

操作步骤总结

  1. 初始化:​​ 根据原始数组 arr构造差分数组 diff

  2. 区间修改:​​ 当需要对 arr的区间 [l, r]增加 k时:

    • diff[l] += k

    • if (r + 1 < n) diff[r + 1] -= k

    • (时间复杂度 O(1))

  3. 查询(还原):​​ 当需要知道修改后的 arr[i]的值时,或者需要得到整个修改后的数组时,对差分数组 diff求前缀和得到 arr

    • (查询单个元素 O(1) - 如果维护了前缀和数组;还原整个数组 O(n))

优点

  • 区间修改效率高:​​ 将 O(n) 的区间修改操作降低到 O(1)。

  • 实现简单:​​ 概念清晰,代码实现容易。

缺点

  • 单点或区间查询效率低:​​ 查询单个元素或区间和需要 O(n) 时间还原前缀和(除非额外维护前缀和数组)。如果查询非常频繁,可能需要结合树状数组或线段树等更高级的数据结构。

应用场景

差分数组特别适用于以下情况:

  • 大量区间修改操作:​​ 问题需要对数组进行多次区间增减操作。

  • 最后统一查询:​​ 所有修改操作完成后,才需要查询最终结果(只需还原一次)。

  • 离线处理:​​ 可以预先记录所有修改操作,最后一次性应用差分并还原。

典型应用:​

  • 航班预订统计(LeetCode 1109)

  • 区间加法(LeetCode 370)

  • 拼车(LeetCode 1094)

  • 处理日程安排、资源分配中的时间段重叠或计数问题。

  • 图像处理中的某些滤镜效果(计算量大时)。

示例

原始数组:​arr = [1, 3, 5, 2, 4]

构造差分数组:​

  • diff[0] = arr[0] = 1

  • diff[1] = arr[1] - arr[0] = 3 - 1 = 2

  • diff[2] = arr[2] - arr[1] = 5 - 3 = 2

  • diff[3] = arr[3] - arr[2] = 2 - 5 = -3

  • diff[4] = arr[4] - arr[3] = 4 - 2 = 2

  • diff = [1, 2, 2, -3, 2]

操作:​​ 给区间 [1, 3](即第2个到第4个元素,值 3, 5, 2)加 5

  • 修改差分数组:

    • l = 1diff[1] += 5-> diff[1] = 2 + 5 = 7

    • r + 1 = 4(4 < 5):diff[4] -= 5-> diff[4] = 2 - 5 = -3

    • diff = [1, 7, 2, -3, -3]

还原修改后的数组 arr':​

  • arr'[0] = diff[0] = 1

  • arr'[1] = arr'[0] + diff[1] = 1 + 7 = 8

  • arr'[2] = arr'[1] + diff[2] = 8 + 2 = 10

  • arr'[3] = arr'[2] + diff[3] = 10 + (-3) = 7

  • arr'[4] = arr'[3] + diff[4] = 7 + (-3) = 4

  • arr' = [1, 8, 10, 7, 4](验证:原区间 [1, 3]3, 5, 2变成了 8, 10, 7,都加了 5

总结

差分数组是一种通过存储相邻元素差值来优化数组区间修改操作的技术。它通过将区间修改转化为两个端点的常数时间修改,极大地提高了处理大量区间增减操作的效率,尤其适用于修改操作频繁而查询操作较少或最后才进行的场景。理解差分数组的构建、修改和还原过程是掌握这一技巧的关键。


文章转载自:

http://G5sL7BoB.qbrdg.cn
http://bkUCxABz.qbrdg.cn
http://34dRJ8D1.qbrdg.cn
http://h2glapsP.qbrdg.cn
http://EDAnj6lp.qbrdg.cn
http://qbEj8AIf.qbrdg.cn
http://JDfHVPWK.qbrdg.cn
http://D7IUsNT5.qbrdg.cn
http://50YugFX0.qbrdg.cn
http://b2RzSHUm.qbrdg.cn
http://4nD2zBS8.qbrdg.cn
http://E4l1Cus0.qbrdg.cn
http://m63uhyec.qbrdg.cn
http://tZFJlz0b.qbrdg.cn
http://qrEdPDei.qbrdg.cn
http://rmEMF4gi.qbrdg.cn
http://2zhXIA6g.qbrdg.cn
http://TzlkjUr2.qbrdg.cn
http://uhVHMU4R.qbrdg.cn
http://dFmI6VP9.qbrdg.cn
http://zPvttEvd.qbrdg.cn
http://giJ2Woyy.qbrdg.cn
http://COrSaClk.qbrdg.cn
http://G2W26SHL.qbrdg.cn
http://E1UXbDld.qbrdg.cn
http://YjYi9qqu.qbrdg.cn
http://EM9TFaPC.qbrdg.cn
http://TjIN3duY.qbrdg.cn
http://wPKguTw7.qbrdg.cn
http://DIJB5jSl.qbrdg.cn
http://www.dtcms.com/a/375885.html

相关文章:

  • 【硬核测评】格行ASR芯片+智能切网算法源码级解析(附高铁场景切换成功率99%方案)
  • 【git】首次clone的使用采用-b指定了分支,还使用了--depth=1 后续在这个基础上拉取所有的分支代码方法
  • AI时尚革命:Google Nano Banana如何颠覆传统穿搭创作
  • OpenCV 高阶 图像金字塔 用法解析及案例实现
  • 【系统分析师】第19章-关键技术:大数据处理系统分析与设计(核心总结)
  • Gears实测室:第一期·音游跨设备性能表现与工具价值实践
  • Next.js中服务器端渲染 (SSR) 详解:动态内容与 SEO 的完美结合
  • C++学习记录(7)vector
  • 【代码随想录算法训练营——Day7】哈希表——454.四数相加II、383.赎金信、15.三数之和、18.四数之和
  • IT 资产管理系统与 IT 服务管理:构建企业数字化的双引擎
  • 手搓Spring
  • LeetCode热题100--230. 二叉搜索树中第 K 小的元素--中等
  • element-plus表格默认展开有子的数据
  • 高带宽的L2 Cache的诀窍
  • 【嵌入式原理系列-第七篇】DMA:从原理到配置全解析
  • 最大异或对问题
  • Tess-two - Tess-two 文字识别(Tess-two 概述、Tess-two 文字识别、补充情况)
  • hot100 之移动零-283(双指针)
  • APP隐私合规评估测试核心要点与第三方APP检测全流程解析
  • ARM汇编与栈操作指南
  • 在 Keil 中将 STM32 工程下载到 RAM 进行调试运行
  • 高效数据操作:详解MySQL UPDATE中的CASE条件更新与性能优化
  • 构建企业级Selenium爬虫:基于隧道代理的IP管理架构
  • Nginx限流与防爬虫与安全配置方案
  • YOLO11训练自己数据集的注意事项、技巧
  • Kafka面试精讲 Day 13:故障检测与自动恢复
  • Linux学习——管理网络安全(二十一)
  • 平衡车 -- PID
  • 【ComfyUI】Flux Krea 微调完美真实照片生成
  • dp类相关问题(1):区间dp