算法学习1 前缀和与差分
一 前缀和是什么?
顾名思义,就是数组里面,以原数组的和作为另一个数组元素的数组。
二 有何益裨?
求数组某个元素内,某一块区域内数据的和,并将他们的时间复杂度由O(n)降低到O(1)。
三 如何使用?
前缀和分为一维前缀和和二维前缀和
有如下几种情况:
设有A[9],成员为{1,2,3,4,5,6,7,8,9};
那么前缀和设为S[9],元素有{1,3,6,10,15,21,28,36,45};
公式如下:
一维前缀和:
S[ i ] - S[ i - 1 ] = A[ i ];所以S[ i ] = A[ i ] + S[ i - 1 ];
( 注意!这也是为什么前缀和与差分数组要从1而不是0开始的原因,因为“ 第一步 ”的空窗期要用A[0]和S[0]去填补。)
二维前缀和:
S[ i ][ j ] = S[ i - 1 ][ j ] + S[ i ][ j - 1] - S[ i - 1 ][ j - 1] + A[ i ][ j ];
OK,前缀和到此结束。
一 差分是什么?
(请注意 ,前缀和与差分的x轴与y轴,和我们平时接触的数学x轴y轴不一样,在这里横为y轴,纵为x轴。)
普遍来说,差分就是前缀和的逆运算。为什么呢?因为你看,前缀和的求值是“依靠原数组的数去求数组在不同位置上的和,并将此坐标作为前缀和数组的下标。”
而我理解的差分是“将原数组作为一个前缀和数组,然后通过逆运算列出每一步参与求和的元素,将这些元素与下标一一对应,便是差分数组了。”
二 差分用途与裨益?
差分既然作为每一步的求和元素,其实在求和过程的每一步重复(加上前元素总和和现元素)都是一个“迭代”的过程,我们可以利用这个特性去反过来“伪造”出一个在“任意范围”里添加了“任意元素”的前缀和数组“A”。
三 差分的使用方法?
差分大致可分为两步,
第一步:拆分析构;第二步:变量重组。
设有原数组Q[9],设立影子数组B[9];
一维差分:
B[ i ] = Q[ i ] - Q[ i - 1];
在Q[ l ] 到Q[ r ]的范围里加上一个常数c;
B[ l ] += c;B[ r + 1 ] -= c;(加一再减去的作用是为了让c完整的覆盖整个{ l ~ r}范围)
最后,伪造原数组:B[ i ] += B[ i - 1]。
二维差分:
内容大致大同小异,唯一不同的就是线性变成了矩阵。
构造insert函数,以便我们逆求前缀和数组:
1 void insert(int x1,int y1,int x2,int y2,int c) 2 { //对b数组执行插入操作,等价于对a数组中的(x1,y1)到(x2,y2)之间的元素都加上了c 3 b[x1][y1] += c; 4 b[x2 + 1][y1] -= c; 5 b[x1][y2 + 1] -= c; 6 b[x2 + 1][y2 + 1] += c; 7 }
把A[ i ][ t ]数组拆分进去的方法:
void insert ( i , t , i , t , A[ i ][ t ] ) ;
或者是直接构造法:
b[i][j] = a[i][j] − a[i − 1][j] − a[i][j − 1] + a[i −1 ][j − 1]
之后都是如法炮制,把需要修改的参数值放入insert函数中。