LeetCode | 370 RangeAddition
https://github.com/dolphinmind/datastructure/tree/datastructure-array-02
分析
数组本身的递归性,差分数组的不变性和可逆性(还原原数组的依据),在left索引上的操作会对当前及后续所有元素产生影响,在right+1索引上进行反操作,会消除这种影响,再进行数组还原,可以使得,如区间加减、区间赋值,可以常数时间内完成这些操作
- 数组本身具有递归性
- 差分数组性质:对于任何常数c,如果将原始数组所有元素加上c,则差分数组不变;从一个数组可以唯一确定其差分数组,反之亦然
利用上面的两个前提中,我们来看
int nums = {8, 2, 6, 3, 1};
int difference = {8, -6, 4, -3, -2};
// 还原[1, 4]部分的差分 numsA[1] = numsA[1], numsA[2] = numsA[1] + difference[2]
int numsA = {8, -6, -2, -5, -7};
nums[1] = numsA[0] + numsA[1] = 2
nums[2] = numsA[0] + numsA[2] = 6
nums[3] = numsA[0] + numsA[3] = 3
nums[4] = numsA[0] + numsA[4] = 1
// numsA[0] 相当于对子差分数组进行整体+8
从上述的例子中发现了什么规律没有?差分数组的子类也始终属于差分,差分数组进行数组还原的过程,每个元素都对其后续所有元素具有同步影响,对差分数组的头部加或减一个常数,就相当于把原数组从头部开始直到后面所有元素进行了相应的操作,因为什么?原数组整体增加/减少一个常量
对差分数组本身毫无影响,而差分数组对初始值非常敏感,
所以在差分数组中[left, right]
- left索引下的数组元素上进行常数增减操作,就是对left索引之后的原数组所有数据元素进行对应操作
- right索引后续数组元素要消除这种传递性,就需要进行反操作
主类
Difference工具类
package com.github.dolphinmind.array.utils;
/**
* @author dolphinmind
* @ClassName Difference
* @description 差分数组
* 性质:对于任何常数c,如果将原始数组的所有元素加上c,则差分数组不变
* 即arr[i] -> arr[i] + c 不改变 diff数组
* @date 2024/8/2
*/
public 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;
}
}
/**
* 返回复原数组
* @return
*/
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;
}
}
RangeAddition类
package com.github.dolphinmind.array;
import com.github.dolphinmind.array.utils.Difference;
/**
* @author dolphinmind
* @ClassName RangeAddition
* @description 370 区间加法
*
* 输入: length = 5, updates = [[1,3,2],[2,4,3],[0,2,-2]]
* 输出: [-2,0,3,5,3]
* @date 2024/8/2
*/
public class RangeAddition {
public int[] getModifiedArray(int length, int[][] updates) {
// nums 初始化为全0
int[] nums = new int[length];
Difference difference = new Difference(nums);
for (int[] update : updates) {
int left = update[0];
int right = update[1];
int constant = update[2];
difference.increment(left, right, constant);
}
return difference.result();
}
}
测试类
package com.github.dolphinmind.array;
import org.junit.Test;
/**
* @author dolphinmind
* @ClassName RangeAdditionTest
* @description
* @date 2024/8/2
*/
public class RangeAdditionTest {
@Test
public void test_getModifiedArray() {
int length = 5;
int[][] updates = {{1, 3, 2}, {2, 4, 3}, {0, 2, -2}};
int[] result = new RangeAddition().getModifiedArray(length, updates);
printArray(result);
}
/**
* @description 打印数组
* @param nums
*/
public void printArray(int[] nums) {
System.out.println();
System.out.print("[");
for (int item : nums) {
System.out.print(item + " ");
}
System.out.print("]");
}
}