差分数组
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;
}
}