[数据结构复习]差分数组

107 阅读4分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第1天,点击查看活动详情

定义

一般差分数组用在,你需要在数组的某一个区间内进行频繁的增减操作

一般题目意思类似于:

给你一个数组 nums,然后又要求给区间 nums[2..6] 全部加 1,再给 nums[3..9] 全部减 3,再给 nums[0..4] 全部加 2,再给…,最后要你输出当前数组

这种题目就很明显使用差分数组

概念

  1. 他的长度和原数组的长度是一致的

  2. diff[i] = nums[i]- nums[i-1]

    其实就是:后一个减去前一个的和

  3. 我们可以利用差分数组求出原数组

    nums[i] = nums[i-1]+diff[i]

举例

现在给你一个数组[8,5,9,6,1]

希望你在将下标[1~3]的值全部加3

  • 那么按照前面说的,首先我们构造出了一个差分数组
  • 然后因为,我们需要将[1...3]的值全部加3
  • 那么我们就可以将diff[1] += 3
  • diff[4] -= 3
  • 这样就可以实现只在[1~3]实现加3

差分数组.png

疑惑:

你可能会对diff[i] += inc,对diff[j+1] -= inc感觉疑惑

我的理解就是,你可以将它理解为一个链

我们知道nums[i] = diff[i]+num[i-1]

  • 那么首先diff[1]加了3以后,很显然,num[1]也就自然而然的加3
  • 那么我们计算nums[2]的时候,nums[2] = diff[2]+ nums[1],
  • 虽然我的diff[2]没有进行加3,但是因为nums[1]加了3,所以,这个nums[2]也就加3
  • 就这样一直到了nums[3]
  • 那么为什么我们需要将diff[j+1] -= inc呢?
  • 因为题目要求,只能让[1,3]3
  • 那为什么设置diff[j+1]而不是diff[j]
  • 因为我们nums[j]也是需要加3
  • nums[j+1] = diff[j+1] +nums[j],j+13,以后,才可以使后面的都变为原来的值

例题

区间加法

链接:370. 区间加法 - 力扣(LeetCode)

题解:

这道就是一个很明显的差分数组题目,但是,略有不同的是,他没有用提供我们原来数组,可是题目也说了,原来数组就是,长度为len的,值为0的数组,那么很显然,他的差分数组也是,长度为len,值全都为0的数组,我们只需要对数组进行操作即可

代码:

var getModifiedArray = function(length: number, update: number[][]){
    // 对一个数组进行频繁操作(进行增减,那么我们就可以使用差分数组)
    // 差分数组:数组长度和原数组长度一样
    // diff[i] = nums[i]-nums[i-1]
    // nums[i] = diff[i]+nums[i-1]
    // 首选先构造差分数组
    let diff = new Array(length).fill(0);
    // console.log(diff)
    // 现在进行操作
    for (let value of update) {
        let firstIndex = value[0];
        let lastIndex = value[1];
        let inc = value[2];
        diff[firstIndex] += inc;
        if (lastIndex + 1 < diff.length) {
            diff[lastIndex + 1] -= inc;
        }
    }
    return getRes(diff);
}

// 根据差分数组求除原料数组
var getRes = function (diff:number[]) {
    // nums[i] = diff[i]+nums[i-1]
    let len = diff.length;
    let nums = new Array(len).fill(0);
    nums[0] = diff[0]
    for (let i = 1; i < diff.length; i++){
        nums[i] = diff[i]+nums[i-1]
    }
    return nums
}

航班预定统计

链接:1109. 航班预订统计 - 力扣(LeetCode)

题解:

  1. 其实这道题也是一个差分数组题,其实和上面这题非常类似
  2. 唯一的不同就是,下标是从1开始的
  3. 但是数组的下标是从0开始的
  4. 所以我们需要将下标减1

代码:

function corpFlightBookings(bookings: number[][], n: number): number[] {
    // 其实他也是一个差分数组,和370那道题目类似
    // 设置差分数组
    let diff = new Array(n).fill(0);
    // 差分数组往里面添加值
    for(let value of bookings){
        let firstIndex= value[0]-1;
        let lastIndex = value[1]-1;
        let count = value[2];
        // 往差分数组里面添加值
        diff[firstIndex] += count;
        if(lastIndex + 1 < n){
            diff[lastIndex+1] -= count;
        }
    } 
    console.log(diff)
    return getRes(diff)
};
// 通过差分数组,求出原来的数组
var getRes = function(diff:number[]){
    // 新建原数组
    let len = diff.length;
    let nums = new Array(len).fill(0)
    // 对数组进行变化
    nums[0] = diff[0];
    for(let i = 1;i<len;i++){
        nums[i] = diff[i]+nums[i-1]
    }
    return nums
}