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

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

一、一维前缀和


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

相关文章
|
23天前
|
算法 API 计算机视觉
人脸识别笔记(一):通过yuface调包(参数量54K更快更小更准的算法) 来实现人脸识别
本文介绍了YuNet系列人脸检测算法的优化和使用,包括YuNet-s和YuNet-n,以及通过yuface库和onnx在不同场景下实现人脸检测的方法。
30 1
|
23天前
|
JSON 算法 数据可视化
测试专项笔记(一): 通过算法能力接口返回的检测结果完成相关指标的计算(目标检测)
这篇文章是关于如何通过算法接口返回的目标检测结果来计算性能指标的笔记。它涵盖了任务描述、指标分析(包括TP、FP、FN、TN、精准率和召回率),接口处理,数据集处理,以及如何使用实用工具进行文件操作和数据可视化。文章还提供了一些Python代码示例,用于处理图像文件、转换数据格式以及计算目标检测的性能指标。
37 0
测试专项笔记(一): 通过算法能力接口返回的检测结果完成相关指标的计算(目标检测)
|
23天前
|
数据可视化 搜索推荐 Python
Leecode 刷题笔记之可视化六大排序算法:冒泡、快速、归并、插入、选择、桶排序
这篇文章是关于LeetCode刷题笔记,主要介绍了六大排序算法(冒泡、快速、归并、插入、选择、桶排序)的Python实现及其可视化过程。
11 0
|
24天前
|
算法
❤️算法笔记❤️-(每日一刷-83、删除排序链表中的重复项)
❤️算法笔记❤️-(每日一刷-83、删除排序链表中的重复项)
29 0
|
13天前
|
算法 安全 数据安全/隐私保护
基于game-based算法的动态频谱访问matlab仿真
本算法展示了在认知无线电网络中,通过游戏理论优化动态频谱访问,提高频谱利用率和物理层安全性。程序运行效果包括负载因子、传输功率、信噪比对用户效用和保密率的影响分析。软件版本:Matlab 2022a。完整代码包含详细中文注释和操作视频。
|
1月前
|
机器学习/深度学习 算法 数据安全/隐私保护
基于MSER和HOG特征提取的SVM交通标志检测和识别算法matlab仿真
### 算法简介 1. **算法运行效果图预览**:展示算法效果,完整程序运行后无水印。 2. **算法运行软件版本**:Matlab 2017b。 3. **部分核心程序**:完整版代码包含中文注释及操作步骤视频。 4. **算法理论概述**: - **MSER**:用于检测显著区域,提取图像中稳定区域,适用于光照变化下的交通标志检测。 - **HOG特征提取**:通过计算图像小区域的梯度直方图捕捉局部纹理信息,用于物体检测。 - **SVM**:寻找最大化间隔的超平面以分类样本。 整个算法流程图见下图。
|
10天前
|
人工智能 算法 数据安全/隐私保护
基于遗传优化的SVD水印嵌入提取算法matlab仿真
该算法基于遗传优化的SVD水印嵌入与提取技术,通过遗传算法优化水印嵌入参数,提高水印的鲁棒性和隐蔽性。在MATLAB2022a环境下测试,展示了优化前后的性能对比及不同干扰下的水印提取效果。核心程序实现了SVD分解、遗传算法流程及其参数优化,有效提升了水印技术的应用价值。
|
11天前
|
机器学习/深度学习 算法 数据安全/隐私保护
基于贝叶斯优化CNN-LSTM网络的数据分类识别算法matlab仿真
本项目展示了基于贝叶斯优化(BO)的CNN-LSTM网络在数据分类中的应用。通过MATLAB 2022a实现,优化前后效果对比明显。核心代码附带中文注释和操作视频,涵盖BO、CNN、LSTM理论,特别是BO优化CNN-LSTM网络的batchsize和学习率,显著提升模型性能。
|
15天前
|
存储
基于遗传算法的智能天线最佳阵列因子计算matlab仿真
本课题探讨基于遗传算法优化智能天线阵列因子,以提升无线通信系统性能,包括信号质量、干扰抑制及定位精度。通过MATLAB2022a实现的核心程序,展示了遗传算法在寻找最优阵列因子上的应用,显著改善了天线接收功率。
|
18天前
|
监控 算法 数据安全/隐私保护
基于三帧差算法的运动目标检测系统FPGA实现,包含testbench和MATLAB辅助验证程序
本项目展示了基于FPGA与MATLAB实现的三帧差算法运动目标检测。使用Vivado 2019.2和MATLAB 2022a开发环境,通过对比连续三帧图像的像素值变化,有效识别运动区域。项目包括完整无水印的运行效果预览、详细中文注释的代码及操作步骤视频,适合学习和研究。