差分、前缀和数组
差分数组
作用:加快区间修改的速度
一般要将数组的[i, j]区间元素都加上或减去一个数,需要从i遍历到j,但是使用差分数组,只需要修改差分数组上两个位置的值即可
int nums[6] = {2, 3, 5, 8, 4, 9}; //待操作的数组
int diff[6];
diff[0] = 0;
for(int i = 1; i < 6; i++){
diff[i] = nums[i] - nums[i - 1];
}
//diff[6] = {0, 1, 2, 3, -4, 5};
diff[1] += 1, diff[5] -= 1; //diff[6] = {0, 2, 2, 3, -4, 4};
nums[0] += diff[0]; //假设nums[0]的前一个元素为0
for(int i = 1; i < 6; i++){
nums[i] = nums[i - 1] + diff[i];
}
//nums[6] = {0, 4, 6, 9, 5, 9};
如果我们想将区间[1, 4]都加上1,只需要diff[1] + 1,diff[4 + 1] - 1即可,因为diff[1]+1表示,1位置上的数与前一个数的差值增加了1,而2与1的差值仍为2,这就相当于2相当于1前面的数加了1,以此内推可知,如果diff[i] + d,就相当于i及之后的值都加上了d,而要做到[i, j]区间的修改,则需要将diff[j + 1] - d,就相当于反向抵消了。
[i to j] + d = diff[i] + d and diff[j + 1] - d;
恢复:
for(int i = 0; i < numsSize; i++){
if(i == 0) nums[i] += diff[i];
else nums[i] = diff[i] + nums[i - 1];
}
前缀和数组
作用:加快区间和的计算
//preSum[i]表示区间[0,i)的元素和
int nums[5] = {1, 3, 5, 7, 9};
int preSum[5 + 1]; //一般是元素个数+1,因为区间是左闭右开的
preSum[0] = 0;
for(int i = 1; i < 5; i++){
preSum[i] = preSum[i - 1] + nums[i];
}
//preSum[6] = {0, 1, 4, 9, 16, 25};
//如果要求区间[i, j]的和,只需要计算preSum[j + 1] - preSum[i]的值即可
//即[0, j + 1) 与 [0, i)两个集合的差(补)集
int Sum_1_to_3 = preSum[4] - preSum[1]; //16 - 1 = 3 + 5 + 7 = 15
Sum[i to j] = preSum[j + 1] - preSum[i];