算法:差分数组技巧

差分数组主要适用场景是频繁对原始数组的某个区间元素进行增减。

和我上文的前缀和技巧的思想有点相似,相当于是前缀和数组的逆操作,

比如:有一个数组nums[1,2,3,2,3,4,6], 要求对它的nums[1..3]区间的数字全部加2,然后再对nums[2..4]区间的数字全部减3,等等一系列加减的操作,然后最后的数组的值是什么?

我们当然可以每次操作都循环一遍,但是这种思路的时间复杂度是O(N),这种情况下对nums频繁的操作,这种思路效率太低,所以这个时候我们就可以利用差分数组技巧,生成一个差分数组,使得这个操作的时间复杂度达到O(1)。

而差分数组是什么?

差分数组就是原始数组相邻元素之间的差,构成的新数组。

我们使用差分数组实现,上代码:

//原数组
int[] nums = new int[1,2,3,2,3,4,6];
//差分数组
int[] diff = new int[nums.length];
//填充差分数组
diff[0] = nums[0];
for(int i = 1; i < diff.length; i++){
    diff[i] = diff[i] - nums[i-1];
}

这样构建好差分数组之后,我们对数组的操作都可以在差分数组上进行,如下:

//参数1:操作起始下标
//参数2:操作结束下标
//参数3:加减的数量
//给i到j区间数据进行加减
private void operation(int i, int j, int val){
    diff[i] += val; 
    if(diff[j+1] > diff.length){
        diff[j+1] -= val;
    }
}

如上对差分数组的操作,假如你想对区间nums[i..j]的元素全部加2,只需在diff[i] +=2,然后在diff[j+1] -= 2即可。

注意为什么要这样操作就可以呢?

先看下通过diff数组反推结果数组的过程,除第一位以外,每一位都需根据前一位的值才能推导出自己的值。

int[] res = new int[diff.length];
//根据差分数组推导结果数组
res[0] = diff[0];
for(int i = 1; i<res.length; i++){
     res[i] = res[i-1] + diff[i];
}

从上面推导结果数组可以看到,每一位都是需要根据前一位的值加差分数组当前下标的值,也就是说我们在操作区间的首位加或者减,数组后面的所有数据都会发生改变,而我们操作是有终点的,所以终点之后的所有数据,就要对操作取逆,也就是说我们在首位加过3,那么我们就要在终点的后一位减3,这就是上面的 diff[j+1] -= 2 的含义。

当然如果 j + 1 大于diff.length 的时候,说明对首位之后的所有数据都进行操作了,也就没有必要 对diff[j+1]进行操作了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值