差分数组——简单解决数组的频繁操作问题
差分数组
说过***前缀和主要适用的场景是原数组不会被改变的情况下,频繁查询某个区间的累加和***;那么差分数组的主要使用场景是***频繁对原始数组的某个区间的元素进行增删***,所以两者的区别就是是否需要对原始数组进行改变。
差分数组和前缀和的思路一样,都需要先创建一个新的差分数组diff,差分数组中存储的都是原数组当前元素与前一个元素的差,即:diff[i] = nums[i] - nums[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]; }
当然,我们也可以反推出原数组,因为我们的要求就是在原数组上进行操作,所以最终一定要返回原数组;
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]; }
我们构建出差分数组之后,就可以对需要操作的区间进行增减操作,如果相对[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 了?***我们可以抽象出一个工具类;
// 差分数组工具类 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; // 当j+1 >= diff.length时,说明是对nums[i]及以后的整个数组都进行修改,那么就不需要再给diff数组减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; } }
下一篇:
PPT基础知识和快捷键的应用