差分数组

91 阅读4分钟

青训营 差分数组一般解法 特例题解 | 豆包MarsCode AI刷题

案例引入

有时候我们遇到需要频繁对数组中某个区间进行加减操作,此时如果正常遍历则会导致时间复杂度增加,而通过差分数组能极大优化这一过程。今日刷题中遇到一道名为打点计数器的区间合并题,通过差分数组能很快求解。本题使用go语言进行解答。

题目描述:

题目初步分析:

在本题中,小明需要计算在给定区间打点后,整个范围内一共有多少点。考虑到本题需要频繁对某个区间修改,因此采用差分数组进行求解:先遍历inputArray来更新差分数组状态,再遍历差分数组得到答案。

题目详解:

  1. 首先初始化所需要设立差分数组,由于本题没有明确整个数字范围大小,因此考虑先设置一个长度较大的数组,再根据所给出inputArray中数字的最小值与最大值来对数组进行切片处理。这样便能满足最后遍历时只需要遍历所需范围。

    cnt := make([]int, 100000001)//设置较大长度的数组
    mx := math.MinInt//初始化最大值
    mn := math.MaxInt//初始化最小值
    
  2. 遍历inputArray来对差分数组进行更新:

    将区间起点值加1,区间终点后一位减1。这样能够保证在遍历差分数组时所得索引值在区间内为1区间外为零。同时每次都判断左边界、右边界与当前最小值最大值,以维护整个区间范围。在遍历inputArray接受根据最大值与最小值来进行切片操作。

    for _, v := range inputArray {
            cnt[v[0]]++//左边界加一
            cnt[v[1]+1]--//右边界减一
            if v[1] > mx {
                mx = v[1] + 1//更新最大值
            }
            if v[0] < mn {
                mn = v[0]//更新最小值
            }
        }
    ​
        cnt = cnt[mn:mx]//进行切片操作
    
  3. 遍历差分数组得到结果:

    在遍历时,当前索引的值更新为前一个索引的值加上当前索引值,如果大于零则说明当前索引被打过点,打点数加一。最终返回打点数则为结果。

    num := 1//区间最左边一定打点
    for i := 1; i < len(cnt); i++ {
        cnt[i] += cnt[i-1]
        if cnt[i] > 0 {
            num++
        }//如果更新后值大于零则说明被打点
    }
    

完整代码如下:

​
func solution(inputArray [][]int) int {
    // Please write your code here
    cnt := make([]int, 100000001)
    mx := math.MinInt
    mn := math.MaxInt
    for _, v := range inputArray {
        cnt[v[0]]++
        cnt[v[1]+1]--
        if v[1] > mx {
            mx = v[1] + 1
        }
        if v[0] < mn {
            mn = v[0]
        }
    }
    num := 1
    cnt = cnt[mn:mx]
    for i := 1; i < len(cnt); i++ {
        cnt[i] += cnt[i-1]
        if cnt[i] > 0 {
            num++
        }
    }
​
    return num
}
​

运行结果如下:

差分数组一般解法:

在解答完本题后,运用豆包AI对差分数组的一般解法进行归纳:

差分数组的基本概念

假设我们有一个原始数组 arr,长度为 n。我们可以构建一个差分数组 diff,其中 diff[i] 表示 arr[i]arr[i-1] 之间的差值。具体来说:

  • diff[0] = arr[0]
  • diff[i] = arr[i] - arr[i-1] 对于 i > 0

差分数组的应用

差分数组主要用于以下两种操作:

  1. 区间更新:对数组 arr 的某个区间 [l, r] 进行加减操作。
  2. 查询单点值:通过差分数组还原出原始数组 arr 中的某个位置的值。

区间更新操作

假设我们要对数组 arr 的区间 [l, r] 进行加 k 的操作。我们可以通过以下步骤在差分数组 diff 中进行更新:

  • diff[l] += k
  • diff[r+1] -= k (如果 r+1 在数组范围内)

查询单点值

通过差分数组 diff,我们可以还原出原始数组 arr 中的某个位置的值。具体来说:

  • arr[i] = diff[0] + diff[1] + ... + diff[i]

总结与思考

本题难度较低,适合作为差分数组算法的入门题进行解答。在使用差分数组时需要考虑左右边界是否取闭区间,且需要明确需要遍历的范围来减少额外消耗。