js实现差分数组

427 阅读2分钟

使用场景

频繁对原始数组的某个区间的元素进行增减,给定一个数组nums,然后又要求给区间nums[1..3]全部加 2,再给nums[2..4]全部加3,再给nums[0..2]全部减2, ... 最后nums数组的值是什么?

  1. 常规思路for循环 时间复杂度是O(N)
  2. 差分数组 时间复杂度O(1) 记录一个差分数组diffdiff[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)