差分数组详述+实战

89 阅读2分钟

差分数组

1.应用

Q:如果给你一个包含5000万个元素的数组,然后会有频繁区间修改操作,那什么是频繁的区间修改操作呢?比如让第1个数到第1000万个数每个数都加上1,而且这种操作时频繁的。此时你应该怎么做? 你很容易想到的是模拟操作,对数组进行遍历操作,在对应区间的每个位置上都+1,但是这种模拟面对数据规模小的情况还算凑合,当出现大规模数据量的情况下,性能会非常差。 一般为了换取更高效的时间复杂度,我们一般采取用空间来换取时间的策略,因此引出今天的主角差分数组

2.概念引入

1.什么是差分数组?

差分数组本质上来说就是一个数组,可以用O(1)的时间修改数组区间

2.差分数组的定义

我们设原数组nums,差分数组diff,当2<=i<=n时,diff[i]=nums[i]-nums[i-1];

3.差分数组的性质

1.当我们需要统一更新区间[l,r](仅+,-操作),我们只需更新diff[l]+=val,diff[r+1]-=val;

2.当我们需要单独查询arr中每一个点的值的时候,我们不难发现令Sn为diff的前缀和,那么arr[i]=S[i]

我们来举一个例子吧

arr=[0,0,0,0,0] 长度为5,存在以下操作
[2,1,3] //在下标[1,3]上的元素进行+2操作(注:起始下标为0)
[1,0,4]
[5,4,4]  
预期最终结果 arr=[1,3,3,3,6]  
因此我们需要准备一个5+2长度的diff数组
diff=[0,0,0,0,0,0,0]
index 0 1 2 3 4 5 6
1 对于[2,1,3]操作:diff[1]+=2,diff[3+1]-=2;
  diff=[0,2,0,0,-2,0,0]
  index 0 1 2 3  4 5 6
2 对于[1,0,4]操作:diff[0]+=1,diff[4+1]-=1;
  diff=[1,2,0,0,-2,-1,0]
  index 0 1 2 3  4  5 6
3 对于[5,4,4]操作:diff[4]+=5,diff[4+1]-=5;
  diff=[1,2,0,0,3,-6,0]
  index 0 1 2 3 4  5 6
对diff求前缀和 S=[1,3,3,3,6,0,0]
        index:  0 1 2 3 4 5 6     

3.实战

1.leetcode1094 拼车

class Solution {
    public boolean carPooling(int[][] trips, int capacity) {
        int n=0;
        for (int[] trip : trips) {
            n=Math.max(trip[2],n);
        }
        int[] dis=new int[n+2];
        //在这里的时候不需要对每个位置进行合法性检查哦,
        //仔细想想dis数组的含义是啥-_-
        for (int[] trip : trips) {
            dis[trip[1]]+=trip[0];
            dis[trip[2]]-=trip[0];
        }
        int sum=0;
        for (int i =0; i < dis.length; i++) {
            sum+=dis[i];
            if(sum>capacity)return false;
        }
        return true;
    }
    
}

2.leetcode1109航班预订统计

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

3.leetcode1679互补操作数最少

class Solution {
    public int minMoves(int[] nums, int limit) {
        int[] diff=new int[2*limit+2];
        int n=nums.length;
​
        for (int i = 0; i <n/2 ; i++) {
            int a=nums[i];
            int b=nums[n-i-1];
​
            int l=2;
            int r=2*limit;
            diff[l]+=2;
            diff[r+1]-=2;
​
            l=1+Math.min(a,b);
            r=limit+Math.max(a,b);
            diff[l]-=1;
            diff[r+1]+=1;
​
            l=a+b;
            r=a+b;
            diff[l]-=1;
            diff[r+1]+=1;
        }
​
        int res=n;
        int sum=0;
        for (int i = 2; i <=2*limit ; i++) {
            sum+=diff[i];
            res=Math.min(res,sum);
        }
        return res;
    }
}

大家周末快乐😊