使用场景
频繁对原始数组的某个区间的元素进行增减,给定一个数组nums,然后又要求给区间nums[1..3]全部加 2,再给nums[2..4]全部加3,再给nums[0..2]全部减2, ...
最后nums数组的值是什么?
- 常规思路for循环 时间复杂度是O(N)
- 差分数组 时间复杂度O(1) 记录一个差分数组
diff,diff[i]就是nums[i]和nums[i-1]之差,如果你想对区间nums[i..j]的元素全部加 3,那么只需要让diff[i] += 3,然后再让diff[j+1] -= 3即可,操作的时候只操作diff,最后通过diff反推出结果
力扣第 370 题「区间加法」
/**
* 你有一个长度为n得数组,初始情况下所有的数字都均为0,k个更新操作
* [startIndex, endIndex, inc]
* 将子数组 A[startIndex ... endIndex]增加inc
* 返回k次操作后的数组
* 输入 length = 5, updates = [[1,3,2], [2,4,3], [0,2,-2]]
* 输出[-2,0,3,5,3]
*/
// 差分数组工具类
class Difference {
/* 输入一个初始数组,区间操作将在这个数组上进行 */
constructor (nums) {
if (!nums.length) return
this.diff = new Array(nums.length).fill(0)
// 构造差分数组
this.diff[0] = nums[0]
for (let i = 1; i< nums.length; i++) {
this.diff[i] = nums[i] - nums[i - 1]
}
}
/* 给闭区间 [i,j] 增加 val(可以是负数)*/
increment(i, j ,val) {
this.diff[i] += val
if(j + 1 < this.diff.length) {
this.diff[j + 1] -= val
}
console.log('increment', this.diff)
}
/* 返回结果数组 */
result() {
const diff = this.diff
let res = new Array(diff.length).fill(0)
// 根据差分数组构造结果数组
res[0] = diff[0]
for(let i = 1; i<diff.length; i++) {
res[i] = res[i - 1] + diff[i]
}
return res
}
}
function getData(length, arr) {
// nums 初始化为全 0
const nums = new Array(length).fill(0)
// 构造差分解法
const df = new Difference(nums);
for(item of arr) {
const i = item[0]
const j = item[1]
const val = item[2]
df.increment(i, j, val)
}
return df.result()
}
const result = getData(5, [[1,3,2], [2,4,3], [0,2,-2]])
console.log('result', result)