如何在常数时间内对数组进行加减操作

74 阅读1分钟

差分数组

使用场景

这个主要出现在数组上,尤其是对一段数组的操作。一般我对于这样的题目都是直接模拟的。但是这要消耗许多的时间0(n),于是我们有没有一种方法是可以直接在O(1)时间内就操作好呢?当然是有的。

差分数组的原理和性质

首先说明什么是差分数组,保留第一位的情况下,后一项-前一项,还原的话就是从第2项开始加前一项就行了。

【x1,x2,x3,x4,x5】-->【x1,x2-x1,x3-x2,x4-x3,x5-x4】

有人说这个与一段数组上的操作有什么关系呢?我们先别急假设我们对一段数x2到x4上加上一个x,然后再来看这个差分数组。我们又能发现什么呢?

【x1,x2,x3,x4,x5】-->【x1,x2+x,x3+x,x4+x,x5】
原本的差分数组为【x1,x2-x1,x3-x2,x4-x3,x5-x4】
  [x1,x2+x-x1,x3+x-x2-x,x4+x-x3-x,x5-x4-x]

我们可以发现与原差分数组相比,除了x2和x5的差分数组发生了变化之外,中间没有发生变化。所以呢?我们没有必要模拟整个过程,我们只需要在 左端点和右端点+1进行修改就行。所以我们再遇到需要修改一段数组上的数时,就可以使用的。

差分数组的模板

int[] solve(int n, int[][] queries) {
    int[] diff = new int[n]; // 差分数组
    for (int[] q : queries) {
        int left = q[0], right = q[1], x = q[2];
        diff[left] += x;
        if (right + 1 < n) {
            diff[right + 1] -= x;
        }
    }
    for (int i = 1; i < n; i++) {
        diff[i] += diff[i - 1]; // 直接在差分数组上复原数组 a
    }
    return diff;
}
​

当然知道这个模板,我们还需要知道一些小细节,比如n,因为数组是从0开始的,而且我们在计算右端点是需要加一的,所以我们题目给的n是经常需要+2或+1的。除此之外我们还有注意,题目的左右端点的范围要特别清楚,right+1有些题目是不需要+1的。

最后

感谢大家看了这些东西,希望你可以学到东西。也欢迎大家观看灵神的算法课堂。本期内容就是借鉴了其特点。里面也有许多练习。欢迎大家观看灵神写的文章leetcode.cn/circle/disc…