数组技巧-差分数组

差分数组

该技巧和前缀和数组一样都是用在数组上的,

前缀和数组是用来简化 任意区间的元素之和的,

差分数组是用来简化 频繁在任意区间减去某个值或者在任意区间加上某个值,最后输出最后的数组结果的

比如,给你一个数组nums[2,4,1,45,21,54,12,43],我需要先将[2,4]都加3,再将[3,6]都减1,再…,最后输出最后的数组结果

如果没学过差分数组,那么应该是使用for循环将范围内的数都进行操作,最后输出数组,

nums的操作十分频繁,这样的效率十分低下

这里我们就使用差分数组来提高我们的效率

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

在这里插入图片描述

i!=0的时候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];
}

diff的还原是先new一个新的数组来存放最后的结果,对于0之后的元素,res[i]等于前一个元素加上当前索引的diff

如果我要将[i,j]区间加2,那么就将diff[i]+=2;diff[j+1]-=2即可

我将diff[i]+=2,即达到res[i]到最后都会被加上2的效果

我将diff[j+1]-=2,即达到res[j+1]之后,会将前面的加2抵消,所以j之后的元素就不会被影响了

我们来和之前的那道前缀和数组一样,抽象出来一个类来处理数组

class Diff{
    private int[] diff;
    public Diff(int[] nums){
        
    }
    public void increase(int left, int right, int step){
        
    }
    public int[] getResult(){
        
    }
}

大家可以先自己写一下

这是实现:

class Diff {
    private int[] diff;

    public Diff(int[] nums) {
        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 void increase(int left, int right, int step) {
        diff[left] += step;
        if (right < diff.length - 1) {
            diff[right + 1] -= step;
        }
    }

    public int[] getResult() {
        int[] result = new int[diff.length];
        result[0] = diff[0];
        for (int i = 1; i < diff.length; i++) {
            result[i] = result[i - 1] + diff[i];
        }
        return result;
    }
}

小试牛刀

接下来就要实践出真知,来看一下这道力扣题,这道题在力扣上是plus会员才可以查看,这里直接将题目简述给大家

力扣370:区间加法
# 370.区间加法
假设你有一个长度为 n 的数组nums,初始情况下所有的数字均为 0,你将会被给出 k 个更新的操作。
其中,每个操作会被表示为一个三元组:[left,right,step],你需要该区间[left,right] (包括left和right)增加step。
请你返回 k 次操作后的数组。
# 示例
len=5,updates=[[1,3,3],[2,4,-5],[0,3,4]]
原数组变为 [0,0,0,0,0]
原数组变为 [0,3,3,3,0]
原数组变为 [0,3,-2,-2,-5]
原数组变为 [4,7,2,2,-5]
result: [4,7,2,2,-5]

# 方法签名
public int[] getModifiedArray(int[] nums, int[][] updates) {
    
}

只要懂了上面的Diff类的写法,这题轻轻松松拿下!

代码:

public int[] getModifiedArray(int[] nums, int[][] updates) {
    int[] diff = new int[nums.length];
    diff[0] = nums[0];
    for (int i = 1; i < diff.length; i++) {
        diff[i] = nums[i] - nums[i - 1];
    }
    for (int[] update : updates) {
        diff[update[0]] += update[2];
        if (update[1] + 1 < diff.length) {
            diff[update[1] + 1] -= update[2];
        }
    }
    int[] result = new int[diff.length];
    result[0] = diff[0];
    for (int i = 1; i < result.length; i++) {
        result[i] = result[i - 1] + diff[i];
    }
    return result;
}

既然我们之前写了Diff那么我们就可以使用它

public int[] getModifiedArray1(int[] nums, int[][] updates) {
    Diff diff = new Diff(nums);
    for (int[] update : updates) {
        diff.increase(update[0], update[1], update[2]);
    }
    return diff.getResult();
}
力扣1109:航班预订统计

本质是一样的,只不过这边需要注意一下索引和编号的对应关系,

class Solution {
    public int[] corpFlightBookings(int[][] bookings, int n) {
        int[] diff = new int[n];
        for (int[] booking : bookings) {
            diff[booking[0] - 1] += booking[2];
            if (booking[1] < n) {
                diff[booking[1]] -= booking[2];
            }
        }
        int[] answer = new int[diff.length];
        answer[0] = diff[0];
        for (int i = 1; i < answer.length; i++) {
            answer[i] = answer[i - 1] + diff[i];
        }
        return answer;
    }
}

相信学完这些,你对差分数组的理解也比较深刻了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

芝麻\n

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值