文章目录
前言
前段时间学习了一维前缀和,一维前缀和可以对数组进行整合操作,今天学习一维差分,一维差分就可以对数组进行区域性加减操作了。
一、差分是什么?
差分与前缀和在算法中往往对应存在,它是一种策略
令b [i]=a[i] −a[i-1] ,即相邻两数的差。
————————————————
二、差分是性质
差分数组可以通过前缀和得到原数组(⭐)
二、一维差分讲解
引入
一个由5个数字组成的数组arr[5]={1,3,7,5,2}
对其进行3次操作
:在[2,4] +5
在[1,3] +2
在[0,2] -3
最后询问1次:arr[]={ }
arr[5]
1 3 7 5 2
如果我们按部就班的进行操作
arr[5]
1 3 7 5 2
1 3 12 10 7
1 5 14 12 7
-2 2 11 12 7
一步一步求最终会得到结过arr[5]={-2,2,11,12,7}
但如果数据很大,这样的解法空间复杂度完全会超出时限,
所以我们引进差分。
先求出差分数组d[i]= arr[i]− arr[i-1] // i>0
d[0]=arr[0]
差分表示的是相邻两数的差(原因)
所以当我们对第n项进行改动时,从第n项以后的
所有数都将会受到相应的影响 。
(可以想象多米诺骨牌,一发而动全身)
如果对第L项进行改动,对第R+1项进行相反的改动,
那么改动的空间只是[L,R](手指推倒第L张多米诺骨牌从L
以后的多米诺骨牌挨个倒地,为牵扯到第R+1张牌时手指支撑
是其没有倒下,所以倒下的即改动的只有[L,R])
这样就好理解了。
这个操作我们称为:差分标记
进行完 差分标记就可以得到所有操作改变后的差分数组,根据这个差分数组,可以用差分的性质对其还原得到所有操作改变后的原数组。
我们将差分标记用到题目中:
首先由arr【】数组确定了的差分数组d【】
再进行±操作
d【2】+5 d【5】-5 //对d【5】-5操作可有可无,越界了
影响的是第2项到第5项(也可以说后面的整个数组,所以对d【5】的操作可有可无)
此时
d 1 2 9 -2 -3 //差分的性质--还原原数组
arr 1 3 12 10 7
剩下的操作几乎相同,就不再讲解
代码操作
代码如下(示例):
#include<iostream>
using namespace std;
int d[6]={0}; //初始化差分数组d,d[6]比
//arr[5]大1防止d[R+1]+-v越界
//也可替换为d[5]={0}
void add(int L,int R,int v)
{
d[L]+=v;
d[R+1]-=v;
}
int main()
{
int arr[5]={1,3,7,5,2};
add(2,4,5);
add(1,3,2);
add(0,2,-3);
for(int i=1;i<5;i++)
d[i]+=d[i-1];
for(int i=0;i<5;i++)
{
arr[i]+=d[i];
cout<< arr[i] <<" ";
}
return 0;
}
总结
一维差分也比较简单,想清楚差分数组和差分标记就可以了,可以想想多米诺骨牌有助于理解。