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

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

一、一维前缀和


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月前
|
算法 API 计算机视觉
人脸识别笔记(一):通过yuface调包(参数量54K更快更小更准的算法) 来实现人脸识别
本文介绍了YuNet系列人脸检测算法的优化和使用,包括YuNet-s和YuNet-n,以及通过yuface库和onnx在不同场景下实现人脸检测的方法。
73 1
|
2月前
|
JSON 算法 数据可视化
测试专项笔记(一): 通过算法能力接口返回的检测结果完成相关指标的计算(目标检测)
这篇文章是关于如何通过算法接口返回的目标检测结果来计算性能指标的笔记。它涵盖了任务描述、指标分析(包括TP、FP、FN、TN、精准率和召回率),接口处理,数据集处理,以及如何使用实用工具进行文件操作和数据可视化。文章还提供了一些Python代码示例,用于处理图像文件、转换数据格式以及计算目标检测的性能指标。
74 0
测试专项笔记(一): 通过算法能力接口返回的检测结果完成相关指标的计算(目标检测)
|
2月前
|
数据可视化 搜索推荐 Python
Leecode 刷题笔记之可视化六大排序算法:冒泡、快速、归并、插入、选择、桶排序
这篇文章是关于LeetCode刷题笔记,主要介绍了六大排序算法(冒泡、快速、归并、插入、选择、桶排序)的Python实现及其可视化过程。
21 0
|
2月前
|
算法
❤️算法笔记❤️-(每日一刷-83、删除排序链表中的重复项)
❤️算法笔记❤️-(每日一刷-83、删除排序链表中的重复项)
34 0
|
16天前
|
算法
基于WOA算法的SVDD参数寻优matlab仿真
该程序利用鲸鱼优化算法(WOA)对支持向量数据描述(SVDD)模型的参数进行优化,以提高数据分类的准确性。通过MATLAB2022A实现,展示了不同信噪比(SNR)下模型的分类误差。WOA通过模拟鲸鱼捕食行为,动态调整SVDD参数,如惩罚因子C和核函数参数γ,以寻找最优参数组合,增强模型的鲁棒性和泛化能力。
|
22天前
|
机器学习/深度学习 算法 Serverless
基于WOA-SVM的乳腺癌数据分类识别算法matlab仿真,对比BP神经网络和SVM
本项目利用鲸鱼优化算法(WOA)优化支持向量机(SVM)参数,针对乳腺癌早期诊断问题,通过MATLAB 2022a实现。核心代码包括参数初始化、目标函数计算、位置更新等步骤,并附有详细中文注释及操作视频。实验结果显示,WOA-SVM在提高分类精度和泛化能力方面表现出色,为乳腺癌的早期诊断提供了有效的技术支持。
|
2天前
|
供应链 算法 调度
排队算法的matlab仿真,带GUI界面
该程序使用MATLAB 2022A版本实现排队算法的仿真,并带有GUI界面。程序支持单队列单服务台、单队列多服务台和多队列多服务台三种排队方式。核心函数`func_mms2`通过模拟到达时间和服务时间,计算阻塞率和利用率。排队论研究系统中顾客和服务台的交互行为,广泛应用于通信网络、生产调度和服务行业等领域,旨在优化系统性能,减少等待时间,提高资源利用率。
|
10天前
|
存储 算法
基于HMM隐马尔可夫模型的金融数据预测算法matlab仿真
本项目基于HMM模型实现金融数据预测,包括模型训练与预测两部分。在MATLAB2022A上运行,通过计算状态转移和观测概率预测未来值,并绘制了预测值、真实值及预测误差的对比图。HMM模型适用于金融市场的时间序列分析,能够有效捕捉隐藏状态及其转换规律,为金融预测提供有力工具。
|
18天前
|
算法
基于GA遗传算法的PID控制器参数优化matlab建模与仿真
本项目基于遗传算法(GA)优化PID控制器参数,通过空间状态方程构建控制对象,自定义GA的选择、交叉、变异过程,以提高PID控制性能。与使用通用GA工具箱相比,此方法更灵活、针对性强。MATLAB2022A环境下测试,展示了GA优化前后PID控制效果的显著差异。核心代码实现了遗传算法的迭代优化过程,最终通过适应度函数评估并选择了最优PID参数,显著提升了系统响应速度和稳定性。
|
10天前
|
机器学习/深度学习 算法 信息无障碍
基于GoogleNet深度学习网络的手语识别算法matlab仿真
本项目展示了基于GoogleNet的深度学习手语识别算法,使用Matlab2022a实现。通过卷积神经网络(CNN)识别手语手势,如&quot;How are you&quot;、&quot;I am fine&quot;、&quot;I love you&quot;等。核心在于Inception模块,通过多尺度处理和1x1卷积减少计算量,提高效率。项目附带完整代码及操作视频。
下一篇
DataWorks