大家好,又见面了,我是你们的朋友全栈君。
参考于 labuladong: 论那些小而美的算法技巧:差分数组
一、什么时候使用差分数组呢?
相信很多人都遇到过这类题:
给定一个原数组长度为 n,查询次数 m ,
每次查询给定一个区间 [l ,r] 和一个整数 k , 使得原数组介于 [l ,r] 之间的元素同时 增 (或减) k
输出最终的数组
num[ 8 , 2 , 6 , 3 , 1 ] m = 2
1 3 1
0 2 3
注:
第一次查询 num = 8 3 7 4 1
第二次查询 num = 11 6 10 4 1
最终 num = 11 6 10 4 1
当然了,每次查询,遍历一下区间 [l ,r] 对其进行修改,结果肯定是对的
但是呢,笔试 和 刷题 时,如果数据给的比较大,比较严苛,多数是会超时,时间复杂度是 O(mn)
二、什么是差分数组 ?
这时就需要用到了差分数组的技巧来解答,
差分数组 : 主要适用场景是频繁对原始数组的某个区间的元素进行增减。
1、首先 构造差分数组 diff ,diff [ i ] = num [ i ] – num [ i – 1 ]
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];
}
通过这个diff差分数组是可以反推出原始数组nums的,代码逻辑如下:
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];
}
2、这样构造差分数组 diff,就可以 快速进行区间增减的操作,如果你想对 区间 [ i , j ] 的元素全部加 3,那么只需要让 diff[ i ] += 3,然后再让 diff[ j + 1 ] -= 3 即可:
原理很简单,回想 diff 数组反推 nums 数组的过程 ,diff [ i ] += 3 意味着给 nums [ i… ] 所有的元素都加了 3,然后 diff [ j + 1 ] -= 3 又意味着对于 nums [ j + 1… ] 所有元素再减 3,那综合起来,是不是就是对 nums [ i … j ] 中的所有元素都加 3 了 。
只要花费 O(1) 的时间修改 diff 数组,就相当于给 nums 的整个区间做了修改。多次修改diff,然后通过 diff 数组反推,即可得到 nums 修改后的结果。
class Difference {
// 差分数组
private int[] diff;
public Difference(int[] nums) {
assert nums.length > 0;
diff = new int[nums.length];
// 构造差分数组
diff[0] = nums[0];
for (int i = 1; i < nums.length; i++) {
diff[i] = nums[i] - nums[i - 1];
}
}
/* 给闭区间 [i,j] 增加 val(可以是负数)*/
public void increment(int i, int j, int val) {
diff[i] += val;
if (j + 1 < diff.length) {
diff[j + 1] -= val;
}
}
public int[] result() {
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];
}
return res;
}
}
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/134177.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...