什么是前缀和?
一维数组前缀和
例如数组nums = [1,2,3,4,5]
则其前缀和数组为qian = [1,3,6,10,15]
,即qian
数组的i
索引位置处的值为nums
数组索引0-i
值的和
则有如下关系:nums[i] = qian[i] - qian[i-1]
注:使用该方法有一最大优势便是可以以
(O1)
的时间复杂度得到某块区间的总和,是典型的牺牲空间换取时间
二维数组前缀和
二维数组的应用和计算
二维数组前缀和是一种在二维矩阵上进行快速区域求和的技术,它是一维前缀和概念的扩展。在二维数组中,前缀和可以帮助我们快速计算任意子矩阵的元素和,这在处理图像处理或者某些区域查询问题时非常有用。
二维前缀和的定义
二维前缀和是指对于一个给定的二维数组a
,我们构建一个新的二维数组sum
,其中sum[i][j]
表示从a[0][0]
到a[i][j]
所有元素的和。这样sum
数组的每个元素都代表了一个矩形区域内元素的总和。
计算二维前缀和
计算二维前缀和的过程可以通过动态规划的方式来完成。对于数组a
中的每个元素a[i][j]
,我们可以根据以下公式来计算sum[i][j]
sum[i][j] = sum[i-1][j] + sum[i][j-1] - sum[i-1][j-1] + a[i][j]
使用二维前缀和求子矩阵和
一旦我们计算出了二维前缀和数组sum
,我们就可以快速求出任意子矩阵的和。假设我们要求从(x1, y1)
到(x2, y2)
形成的子矩阵的和,我们可以使用以下公式
subSum = sum[x2][y2] - sum[x1-1][y2] - sum[x2][y1-1] + sum[x1-1][y1-1]
代码实现
1 | public class PrefixSum { |
差分法
定义
对于已知有n
个元素的一维数列nums
,我们可以建立记录它与每项与前一项得差值得差分数组f
;显然,f[1] = nums[1] - 0 = nums[1]
; 对于整数 i∈[2,n]
,我们让f[i]=nums[i]-nums[i-1]
。将对nums
的一些操作转移至f
数列,最终合并f
得到nums
的一种操作,叫做差分法。
举个栗子
- 例如 nums=[3,4,1,5,6,2,7,9]
- 即,f=[3,1,-3,4,1,-4,5,-2]
当我们需要对数组的[1,6]
,这个区间的数+1
,并求处区间+1
后数组的值 - 此时,我们只需要对
f
数组的左边界第1
项+1
,对f
数组的右边界第7
项-1
,此时f=[4,1,-3,4,1,-4,4,2]
,因为第一项+1
,导致1-6
项的差值都+1
了,即完成对给定区间进行+1
操作
差分法的用途
- 快速处理区间加减操作
- 优化时间复杂度,也是典型的牺牲空间换时间
- 对数组f求前缀和即可得到原数组nums
代码实现
对给定数组求差分数组
1 | public class Main{ |
对给定数组求差分数组后通过前缀和得到原数组
1 | public class Main{ |