差分数组——简单解决数组的频繁操作问题

差分数组

上一文中说过***前缀和主要适用的场景是原数组不会被改变的情况下,频繁查询某个区间的累加和***;那么差分数组的主要使用场景是***频繁对原始数组的某个区间的元素进行增删***,所以两者的区别就是是否需要对原始数组进行改变。

差分数组和前缀和的思路一样,都需要先创建一个新的差分数组diff,差分数组中存储的都是原数组当前元素与前一个元素的差,即:diff[i] = nums[i] - nums[i-1],由此我们可以构建一个差分数组,并给数组中的每个元素赋值;

int[] diff = new int[nums.length];
// 为差分数组赋值
diff[0] = nums[0];
for (int i = 1; i < nums.length; i++) {
    diff[i] = nums[i] - nums[i - 1];
}

当然,我们也可以反推出原数组,因为我们的要求就是在原数组上进行操作,所以最终一定要返回原数组;

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

我们构建出差分数组之后,就可以对需要操作的区间进行增减操作,如果相对[i,j]区间的元素全部加3,只需要让diff[i] += 3,然后再让diff[j+1] -= 3即可;***原理很简单,回想diff数组反推nums数组的过程,diff[i] += 3意味着给nums[i…]所有的元素都加了 3,然后diff[j+1] -= 3又意味着对于nums[j+1…]所有元素再减 3,那综合起来,是不是就是对nums[i…j]中的所有元素都加 3 了?***我们可以抽象出一个工具类;

// 差分数组工具类
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];
        }
    }

    /* 给闭区间 [i,j] 增加 val(可以是负数)*/
    public void increment(int i, int j, int val) {
        diff[i] += val;
        // 当j+1 >= diff.length时,说明是对nums[i]及以后的整个数组都进行修改,那么就不需要再给diff数组减val
        if (j + 1 < diff.length) {
            diff[j + 1] -= val;
        }
    }

    /* 返回结果数组 */
    public int[] result() {
        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;
    }
}

最后,感觉差分数组这种方式很巧妙,这都是从这位大佬那里学到的->labuladong,可以关注其微信公众号进行算法学习。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值