差分数组的主要适用场景是频繁对原始数组的某个区间的元素进行增减。

比如说,我给你输入一个数组 nums,然后又要求给区间 nums[2..6] 全部加 1,再给 nums[3..9] 全部减 3,再给 nums[0..4] 全部加 2,再给...

一通操作猛如虎,然后问你,最后 nums 数组的值是什么?

常规的思路很容易,你让我给区间 nums[i..j] 加上 val,那我就一个 for 循环给它们都加上呗,还能咋样?这种思路的时间复杂度是 O(N),由于这个场景下对 nums 的修改非常频繁,所以效率会很低下。

这里就需要差分数组的技巧,类似前缀和技巧构造的 preSum 数组,我们先对 nums 数组构造一个 diff 差分数组,diff[i] 就是 nums[i] 和 nums[i-1] 之差:

 

 

package com.wang;

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];
        }
    }

    public static void main(String[] args) {
        int[] a = new int[]{1, 2, 3, 4, 5, 6};
        Difference difference = new Difference(a);
        difference.increment(0, 2, 3);
        for (int i : difference.getDiff()) {
            System.out.println(i);
        }


    }

    public void increment(int i, int j, int val) {
        //根据差分数组反推原始数组时改变第一个 后面的依据前面的数据 所以改变第一个就是改变了后面所有的
        diff[i] += val;
        //如果 j在范围内就不用减去增加的了
        if (j + 1 < diff.length) {
            diff[j + 1] -= val;
        }

    }

    public int[] getDiff() {
        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;
    }
}

 

posted on 2023-07-23 14:55  upupup-999  阅读(11)  评论(0编辑  收藏  举报