【有营养的算法笔记】基础算法 —— 推导证明前缀和与差分

简介: 【有营养的算法笔记】基础算法 —— 推导证明前缀和与差分

一、一维前缀和


1、算法推导


前缀和,从名字上看,我们就大概能知道算法的作用。前缀,就是某位置之前的所有数,为该数的前缀,前缀和,就是对该位置前缀的元素进行求和。


前缀和的模板其实非常简单,它更像是一种思想。


前缀和思想可以快速地解决问题,看个例子:


假如给定一段序列,需要你求出 [ l , r ] [l, r] [l,r] 区间的和,该如何求?

   最简单的方式就是通过 for 循环遍历一遍,时间复杂度为 O ( N ) O(N) O(N)

   而 前缀和算法 ,能在 O ( 1 ) O(1) O(1) 的时间复杂度完成


接下来我们来看,前缀和算法是如何在 O ( 1 ) O(1) O(1) 的时间复杂度求出和的:


前缀和算法主要分为两步,预处理 和 查询 :假设 a , S a, S a,S 分别为 原数组 和 前缀和数组。

预处理 :


预处理就是求 前缀和数组 。对于前缀和数组 s s s ,其中元素满足 S [ i ] = a [ 1 ] + a [ 2 ] + a [ 3 ] . . . a [ i ] S[i] = a[1] + a[2] + a[3] ... a[i] S[i]=a[1]+a[2]+a[3]...a[i]


求前缀和时,下标从 1 1 1 开始。


大体过程如下:

for (int i = 1; i <= n; i++) {
        s[i] = s[i - 1] + q[i];
    }




前缀和数组每项 s[i] 是它的前一项  s[i−1] 加上原数组  a[i] 。

因为前缀和数组的前一项 s[i−1] ,是 a a a 数组中前  i−1 中前 i−1 项的值嘛,所以求 s[i] 时只要加上  a[i] 就可以计算出来前 i i i 项的前缀和了。


查询:


查询就是求给定区间 [l,r] 的值。现在由于求出了前缀和数组,那么查询时只要一步S[r]−S[l−1] ,就可以求出结果。


下面讲一下原理:

S 是前缀和数组,那么 S 中每一个位置元素都是  a 数组的前缀和,由此可得:


image.png



通过这一步骤,它们相同的元素被 抵消 ,最终结果就是 区间 [ l , r ] [l, r] [l,r] 的值 。


所以,我们发现,前缀和多开了一个数组,以达到优化计算时间的效果,是典型的 以空间换时间 的算法。



2、代码实现


接下来做道前缀和例题练练手。


链接:795. 前缀和

描述:

输入一个长度为  n 的整数序列。


接下来再输入m 个询问,每个询问输入一对  l,r。


对于每个询问,输出原序列中从第  l 个数到第r 个数的和。


输入格式:

第一行包含两个整数 n 和  m 。


第二行包含 n 个整数,表示整数数列。


接下来 m 行,每行包含两个整数l 和r ,表示一个询问的区间范围。


输出格式:


共 m 行,每行输出一个询问的结果。


数据范围:


 1≤l≤r≤n

   1≤n,m≤100000

  −1000≤数列中元素的值≤1000



输入样例:

5 3
2 1 3 6 4
1 2
1 3
2 4


输出样例:

3
6
10


思路 :典型的前缀和例题,思路我们上面已经讲过一遍了,直接开始写代码:


963318a3634674f4f0b036d3238290b1.png




二、二维前缀和


二维前缀和是一维前缀和的加强。


从前只能求一维序列的前缀和,现在能求二维,也就是矩阵的前缀和。


1、算法推导


接下来看 二维前缀和数组 是如何构造的:

947fc20962f5cbd1791317dbd70fabf4.png


假设给定二维矩阵 a和s , s 为前缀和矩阵,这里我们设定一个前提:竖直方向我们统一称为长,横平的边我们统一称为宽,以便我们描述图形。


假如要求 点  (i,j) 的前缀和,那么对于图中,以i,j 为长和宽的矩阵就是 点  (i,j) 的前缀和。


观察上图,可以得到面积公式:


一整块矩形面积=紫色面积+绿色面积+蓝色面积+红色面积

但是,对于矩阵的面积,有些地方是无法单独计算的,比如绿色区域,只能算以  i−1 为长, j 为高的面积。


所以,我们实际计算时,真正的计算公式 为:

一整块矩形面积=以 i−1 为长以 j 为高的矩形面积+以 i 为长以 j−1 为高的矩形面积−紫色面积 + 红色面积

以图表示:


93b999b45934999dd3736627cbb11019.png


至于为什么要加 紫色区域 呢?这是因为在加绿色矩阵和蓝色矩阵的时候,加了两次 紫色区域 ,所以需要去掉重复的这一块。

而这里的每一个与长和宽有直接关联的区域其实就是这一块区域的 前缀和 ,在  s 矩阵中都可以表示出来,而 红色小方格的面积 则是a 矩阵当前位置的元素,所以我们可以得到 二维矩阵前缀和预处理公式 :

s[i][j]=s[i1][j]+s[i][j1]s[i1][j1]+a[i][j]



那么我们构造过程的代码也就可以写出来了:

for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + a[i][j];
        }
    }


而对于二维前缀和,我们的题型通常是求 子矩阵的和 ,比如:

00f8c4bdd6723ef058c18a465fe84412.png



以我们平常的思维方式,就是 两层循环遍历一下 ,时间复杂度为 O ( N × M ) O(N \times M) O(N×M)。


但是如果我们使用 前缀和 呢?实际上只需要 O ( 1 ) O(1) O(1) 的时间复杂度,是非常快的,但是前提得有公式,所以我们得先把公式推导出来。


推导过程 :


我们再进行严格的区域划分,画一张较为详细的图:


同样的这里设定前提:竖直方向的边统一称为长,横平方向的边统一称为宽,以便我们描述图形。


54a9e8ccf1baffb312d3be7147d764eb.png



根据上图,我们可以得出公式:

蓝色面积=x2为长,y2为宽的区域面积黄色面积绿色面积紫色面积


但是这里的区域面积也是不好算一小块的,区域的面积的长和宽要从 (1,1) 出发,所以我们 真正的公式 为:

蓝色面积=x2为长y2为宽的区域面积x11为长y2为宽的区域面积x2为长y11为宽的区域面积+紫色面积

 

加上 紫色面积 的原因是,我们减去了两块 紫色面积 ,需要补上一个。

同样的,这里每块区域的面积,实际上就是 前缀和 ,比如 紫色面积就是 a a a 矩阵中以 x 1 − 1 x1- 1 x1−1 为长, y 1 − 1 y1 - 1 y1−1 的区域面积,前缀和形式就直接为 s [ x 1 − 1 ] [ y 1 − 1 ] s[x1 -1][y1 - 1] s[x1−1][y1−1]。

所以这里写出我们的 查询公式 :

蓝色面积=s[x2][y2]s[x11][y2]s[x2][y11]+s[x11][y11]


到这里,我们的前缀和的核心公式都已经推导出来了,在做题目是就很方便了,只需要:预处理 + 查询


2、代码实现


链接796. 子矩阵的和


对于每个询问输出子矩阵中所有数的和。

输入格式:


第一行包含三个整数  n,  m,  q 。


接下来 n 行,每行包含  m 个整数,表示整数矩阵。


接下来  q 行,每行包含四个整数 x1,y1,x2,y2 ,表示一组询问。


输出格式:

   q 行,每行输出一个询问的结果。



数据范围:


1≤n,m≤1000

1≤q≤200000

1≤x1≤x2≤n

1≤y1≤y2≤m

−1000≤矩阵内元素的值≤1000


输入样例

3 4 3
1 7 2 4
3 6 2 8
2 1 2 3
1 1 2 2
2 1 3 4
1 3 3 4

输出样例

17
27
21



思路

上面公式我们推导过了,直接预处理 + 查询即可:

e6469757ba37b8acfdb3728c7f41a8de.png

相关文章
|
2月前
|
机器学习/深度学习 传感器 算法
【高创新】基于优化的自适应差分导纳算法的改进最大功率点跟踪研究(Matlab代码实现)
【高创新】基于优化的自适应差分导纳算法的改进最大功率点跟踪研究(Matlab代码实现)
229 14
|
2月前
|
机器学习/深度学习 边缘计算 分布式计算
基于差分进化算法的微电网调度研究(Matlab代码实现)
基于差分进化算法的微电网调度研究(Matlab代码实现)
135 1
|
5月前
|
机器学习/深度学习 算法
基于差分进化灰狼混合优化的SVM(DE-GWO-SVM)数据预测算法matlab仿真
本项目实现基于差分进化灰狼混合优化的SVM(DE-GWO-SVM)数据预测算法的MATLAB仿真,对比SVM和GWO-SVM性能。算法结合差分进化(DE)与灰狼优化(GWO),优化SVM参数以提升复杂高维数据预测能力。核心流程包括DE生成新种群、GWO更新位置,迭代直至满足终止条件,选出最优参数组合。适用于分类、回归等任务,显著提高模型效率与准确性,运行环境为MATLAB 2022A。
|
8月前
|
机器学习/深度学习 算法 机器人
强化学习:时间差分(TD)(SARSA算法和Q-Learning算法)(看不懂算我输专栏)——手把手教你入门强化学习(六)
本文介绍了时间差分法(TD)中的两种经典算法:SARSA和Q-Learning。二者均为无模型强化学习方法,通过与环境交互估算动作价值函数。SARSA是On-Policy算法,采用ε-greedy策略进行动作选择和评估;而Q-Learning为Off-Policy算法,评估时选取下一状态中估值最大的动作。相比动态规划和蒙特卡洛方法,TD算法结合了自举更新与样本更新的优势,实现边行动边学习。文章通过生动的例子解释了两者的差异,并提供了伪代码帮助理解。
650 2
|
算法 索引
HashMap扩容时的rehash方法中(e.hash & oldCap) == 0算法推导
HashMap在扩容时,会创建一个新数组,并将旧数组中的数据迁移过去。通过(e.hash & oldCap)是否等于0,数据被巧妙地分为两类:一类保持原有索引位置,另一类索引位置增加旧数组长度。此过程确保了数据均匀分布,提高了查询效率。
239 2
|
算法 API 计算机视觉
人脸识别笔记(一):通过yuface调包(参数量54K更快更小更准的算法) 来实现人脸识别
本文介绍了YuNet系列人脸检测算法的优化和使用,包括YuNet-s和YuNet-n,以及通过yuface库和onnx在不同场景下实现人脸检测的方法。
546 1
|
JSON 算法 数据可视化
测试专项笔记(一): 通过算法能力接口返回的检测结果完成相关指标的计算(目标检测)
这篇文章是关于如何通过算法接口返回的目标检测结果来计算性能指标的笔记。它涵盖了任务描述、指标分析(包括TP、FP、FN、TN、精准率和召回率),接口处理,数据集处理,以及如何使用实用工具进行文件操作和数据可视化。文章还提供了一些Python代码示例,用于处理图像文件、转换数据格式以及计算目标检测的性能指标。
310 0
测试专项笔记(一): 通过算法能力接口返回的检测结果完成相关指标的计算(目标检测)
|
1月前
|
机器学习/深度学习 算法 机器人
【水下图像增强融合算法】基于融合的水下图像与视频增强研究(Matlab代码实现)
【水下图像增强融合算法】基于融合的水下图像与视频增强研究(Matlab代码实现)
203 0
|
1月前
|
数据采集 分布式计算 并行计算
mRMR算法实现特征选择-MATLAB
mRMR算法实现特征选择-MATLAB
150 2
|
2月前
|
传感器 机器学习/深度学习 编解码
MATLAB|主动噪声和振动控制算法——对较大的次级路径变化具有鲁棒性
MATLAB|主动噪声和振动控制算法——对较大的次级路径变化具有鲁棒性
203 3

热门文章

最新文章