• 【CSP考点回顾】差分数组


    差分数组是高效处理数组区间修改问题的方法,适用于对原始数组的连续区间频繁地进行增加或减少操作的情形

    • 例如,输入一个数组 n u m s nums nums,要求给区间 n u m s [ 2...6 ] nums[2...6] nums[2...6] 全部加1,再给 $nums[3…9] $ 全部减3,再给 n u m s [ 0...4 ] nums[0...4] nums[0...4] 全部加2,再给……问:最后 n u m s nums nums 数组中各元素的值是什么?
    • 【常规思路】:使用 for 循环给给区间 n u m s [ i . . j ] nums[i..j] nums[i..j] 加上 v a l val val,该思路的时间复杂度是 O ( N ) O(N) O(N)。由于这个场景下对 n u m s nums nums 的修改非常频繁,所以效率会很低。
    • 【差分数组】:类似前缀和构造的 p r e f i x prefix prefix 数组,对 n u m s nums nums 数组构造 d i f f diff diff 差分数组, d i f f [ i ] = n u m s [ i ] − n u m s [ i − 1 ] diff[i] = nums[i] - nums[i-1] diff[i]=nums[i]nums[i1]

    1.差分数组

    差分数组,记为 d i f f diff diff,是根据原数组 n u m s nums nums 构建的一个新数组,其中 d i f f [ i ] diff[i] diff[i] 表示 n u m s [ i ] nums[i] nums[i] n u m s [ i − 1 ] nums[i - 1] nums[i1] 的差值。对于数组的第一个元素, d i f f [ 0 ] = n u m s [ 0 ] diff[0] = nums[0] diff[0]=nums[0],因为没有前一个元素与之比较。差分数组的主要优势在于它可以快速、高效地对原始数组的任意连续区间进行修改。

    2.差分数组的构造

    构建差分数组 d i f f diff diff,遵循以下步骤:

    1. 初始化 d i f f diff diff 数组,使其长度与原数组 n u m s nums nums 相同。
    2. 设定 d i f f [ 0 ] = n u m s [ 0 ] diff[0] = nums[0] diff[0]=nums[0]
    3. 对于 d i f f diff diff 数组中的其他元素,执行 d i f f [ i ] = n u m s [ i ] − n u m s [ i − 1 ] diff[i] = nums[i] - nums[i - 1] diff[i]=nums[i]nums[i1]
    int[] diff = new int[nums.length];
    diff[0] = nums[0];
    for (int i = 1; i < nums.length; i++) {
        diff[i] = nums[i] - nums[i - 1];
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    请添加图片描述

    3.使用差分数组进行区间修改

    当需要对原数组 n u m s nums nums 的连续区间 [ i . . j ] [i..j] [i..j] 进行修改,即对该区间内所有元素增加或减少某个值 v a l val val 时,我们只需要更新差分数组 d i f f diff diff

    • d i f f [ i ] + = v a l diff[i] += val diff[i]+=val
    • 如果 j + 1 < n u m s . l e n g t h j + 1 < nums.length j+1<nums.length,则 d i f f [ j + 1 ] − = v a l diff[j + 1] -= val diff[j+1]=val

    这样,我们就在 O ( 1 ) O(1) O(1) 的时间复杂度内完成了区间的修改,而不需要遍历整个区间。原理很简单,回想 d i f f diff diff 数组反推 n u m s nums nums 数组的过程, d i f f [ i ] + = v a l diff[i] += val diff[i]+=val 意味着给 n u m s [ i . . ] nums[i..] nums[i..] 所有的元素都加了 v a l val val,然后 d i f f [ j + 1 ] − = v a l diff[j+1] -= val diff[j+1]=val 又意味着对于 n u m s [ j + 1.. ] nums[j+1..] nums[j+1..] 所有元素再减 v a l val val。综合起来,就是对 n u m s [ i . . j ] nums[i..j] nums[i..j] 中的所有元素都加 v a l val val

    • 如,对 [ 2..4 ] [2..4] [2..4] 全部+8,即 d i f f [ 2 ] + = 8 diff[2] += 8 diff[2]+=8 d i f f [ 5 ] − = 8 diff[5] -= 8 diff[5]=8

    请添加图片描述

    4.从差分数组还原原数组

    修改完差分数组后,可以通过以下步骤还原修改后的原数组 n u m s nums nums

    1. 初始化结果数组 r e s res res,使其长度与 d i f f diff diff 相同。
    2. 设定 r e s [ 0 ] = d i f f [ 0 ] res[0] = diff[0] res[0]=diff[0]
    3. 对于 r e s res res 数组中的其他元素,执行 r e s [ i ] = r e s [ i − 1 ] + d i f f [ i ] res[i] = res[i - 1] + diff[i] res[i]=res[i1]+diff[i]
    int[] res = new int[diff.length];
    res[0] = diff[0];
    for (int i = 1; i < diff.length; i++) {
        res[i] = res[i - 1] + diff[i];
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    本文部分内容参考自:【labuladong】前缀和/差分数组技巧精讲

  • 相关阅读:
    电脑删除的文件如何找回?
    stm32|esp8266|阿里云平台|温湿度
    JAVA 开发中常用的工具有哪些?
    基于PHP+MySQL的服装购物商城系统#毕业设计
    python的练习
    Spring 是如何解决循环依赖的?
    如何写好一篇高质量计算机科学论文?
    CMU15445-project2-坑和收获总结
    ant design ant design Pro 中的table横向与纵向合并问题
    JAVA单位职工房产管理计算机毕业设计Mybatis+系统+数据库+调试部署
  • 原文地址:https://blog.csdn.net/fzy2003/article/details/136520047