差分数组的理解
差分数组的理解
差分数组概念
差分数组是一个数组 存放的是相邻数据之间的差值
计算差分数组
public int[] computeDiff(int[] nums){
int length = nums.length;
int[] diff = new int[length];
for(int i = 0; i < length - 1; ++i){
diff[i + 1] = nums[i + 1] - nums[i];
}
}
比如: 初始的数组为:nums[] = {0, 2, 5, 4, 9, 7, 10 ,0}
差分数组用法
差分数组是一个辅助数组 它表示了某个数组的变化 一般用来对数组进行区间修改的操作
这里举一个例子来帮助理解/注意这里的区间指的是下标的区间 不是数值大小的区间
- 将区间[1, 4]的数值全部加上3
- 将区间[3, 5]的数值全部减去5
暴力计算当然可以 但是如果数据量很大的时候 (比如:\(1e5\)) 经常会超出时间限制
将数组
nums中的元素全部加上或者减去某个数组 差分数组不会发生任何变化
-
对于区间[1, 4]的所有操作 只会改变两个差分区间这位置的值 : \(nums[1]\) 和 \(nums[5]\)
- 因为\(nums[1]\)发生了变化 所以它的\(diff[1] = nums[1] - nums[0]\)也会发生变化
- 同理: \(nums[4]\)发生了变化 所以影响了\(nums[5]\)的值
-
进行操作[2]
代码实现
// 假设一共进行 n 次操作
while(n--){
// 里面的 left right 和 change 是我们需要用到的操作数
computeNewDiff(diff, left, right, change);
}
public void computeNewDiff(int[] diff, int left, int right, int change){
diff[left] += change;
diff[right + 1] -= change;
}
获取最终修改后的nums数组的修改值
for(int i = 1; i <= n; ++i){
nums[i] = nums[i - 1] + b[i];
}
利用差分数组解题1674. 使数组互补的最少操作次数
首先我们确定可计算范围 题目中给出的数字的变化范围是:\([1, limit]\) 所以两个数字的和的取值范围是:\([2, 2 * limit]\)
然后记录这对数字组的最大值int max = Math.max(nums[i], nums[n - i - 1])和最小值int min = Math.min(nums[i], nums[n - i - 1])同可变化的情况进行分类讨论:
注意这里是怎么构造区间的:我们用两个数字的和作为区间上下界 什么意思呢?
显然我们一次变化的值最小为\(max = 1\)即\(min + 1\) 最大为\(min = limit\) 即\(max + limit\) 所以我们有以下结论
- 对于区间在\([2, min]\) 这个区间里面的值 我们需要变化两次 \(+2\) 才能够达到目的[缩小\(max 和 min\)]
- 对于区间在\([min + 1, min + max - 1]\)我们只需要变化二者里面的一个\(+1\)就可以达到目的[增大\(min\)或者缩小\(max\)]
- 对于\(min + max\)而言 无需变化
- 对于区间在\([min + max + 1, max + limit]\) 我们只需要变化\(min\)值即可 \(+1\)
- 对于区间在\([max + limit + 1, limit + limit]\) 我们需要变化两个值 \(+2\)
所以我们建立一个差值数组int[] diff = new int[limit * 2 + 1];用来记录差值
对于我们引入的每一个数字对 都相当于对这个差值数组做 增加或者减小操作 操作的区间见上方
这样每次我们都能够获取对区间操作之后的差分数组的结果
class Solution {
public int minMoves(int[] nums, int limit) {
int n = nums.length;
int[] delte = new int[2 * limit + 2];
for(int i = 0; i < n / 2; ++i){
int low = 1 + Math.min(nums[i], nums[n - i - 1]);
int high = Math.max(nums[i], nums[n - i - 1]) + limit;
int sum = nums[i] + nums[n - i - 1];
delte[low]--;
delte[sum]--;
delte[sum + 1]++;
delte[high + 1]++;
}
int ans = n;
int now = n;
for(int i : delte){
now += i;
ans = Math.min(now, ans);
}
return ans;
}
}

浙公网安备 33010602011771号