首页 > 其他分享 >前缀和

前缀和

时间:2023-11-05 19:45:46浏览次数:22  
标签:Arr 前缀 复杂度 元素 数组 Sum

AcWing笔记——前缀和

前言

数组的前缀和,代表着一个数组前N个数的和。主要用于优化这样一种场景:

当题目要求进行求出一个数组从下标 \(i\) 到下标 \(j\) 之间的元素的和,且会多次进行这种操作时,我们可以使用前缀和的方法来优化求和的过程。

时间复杂度对比:

  • 若使用for循环遍历整个数组,对于n次操作,时间复杂度会达到O(n2)的级别,可见非常的耗时。
  • 若使用前缀和的方法,我们要在原数组的基础上求出其前缀和数组,对应的代码如下
	for(int i = 1 ;i < = length; i++)
		Sum[i] = Sum[i-1] + Arr[i]; 

显然求出前缀和只需要遍历一遍原数组即可,时间复杂度为O(n)。而求出前缀和之后,对于每次对\(i\) 以及 \(j\) 之间和的询问,都可以这样求出 \(Ans = S[j] - S[i-1]\)。可以看出对于每次询问,求出答案的时间复杂度是O(1)数量级的。因此整个题目的时间复杂度也就从n方复杂度优化到了线性的复杂度。

\(1.\) 一维前缀和

现在让我们先考虑一维数组的前缀和

对于一个一维数组Arr[N],我们定义其前缀和数组为Sum[N]。
为方便起见,Arr以及Sum从1开始计数,Arr[0] = 0

从前言中对前缀和的定义,前缀和即为数组中前n个数的和。如Sum[6]代表着即为数组中前6个数的和,而Sum[7]代表着数组中前7个数的和。不难看出,Sum[7] = Sum[6] + Arr[7]。

这样我们就找出了对于前n个数的和的递推公式,即\(Sum[N] = Sum[N-1] +Arr[N]\)

因此要求前缀和,只需扫描一遍数组,递推求即可,代码如下

for(int i = 1 ;i < = length; i++)
		Sum[i] = Sum[i-1] + Arr[i]; 

注意这里Arr[0] = 0,且下标从1开始,因此不需要考虑数组越界的问题

求出前缀和数组之后,若要求原数组从 \(i\) 到 \(j\) 的元素和,可以知道\(S[j]\)是从1加到\(j\)的元素之和,而\(S[i-1]\)为从1加到\(i-1\)的元素之和。那么从\(i\)加到\(j\)的元素之和即为\(S[j] - S[i-1]\)。

\(2.\) 二维前缀和

接下来我们将情况推广至二维数组前缀和

对于二维数组Arr[M][N],给出一个点(i,j),我们称S[i][j]代表着数组Arr以(1,1)以及(i,j)为对角点的矩形中元素之和。
image

如上图,每一个方格代表一个数组元素,而前缀和S[i][j]即为(1,1)与(i,j)连成对角线的矩形内方格元素之和。

定义原数组为A[N][M],其前缀和数组为S
我们可以从递推的思想来考虑这样一个二维前缀和的求法。
\(S[i][j] = S[j-1][i] + S[i][j-1] + S[j-1][i-1] + A[i][j] - 2S[i-1][j-1]\)
即\(S[i][j] = S[j-1][i] + S[i][j-1] + A[i][j] - S[i-1][j-1]\)
即i,j处的前缀和可以由其相邻的前缀和求出。
求二维前缀和的代码如下

	for (int i = 1; i <= N; i++)
	{
		for (int j = 1; j <= M; j++)
		{
			S[i][j] = S[i - 1][j] + S[j][i - 1] + A[i][j] - S[i - 1][j - 1];
		}
	}

当我们要用到前缀和求由(x1 , y1)(x2 , y2)两点所构成的对角线的矩形内元素和时
image

如上图,要求(k,l)以及(i,j)之间的元素和,则可以看出answer = S[i][j]减去三部分,分别为S[i-1][j-1] S[i][l-1] S[k-1][j],而且在减去后面的两个块的时候,会重复多减去两次S[i-1][j-1],于是结果再加上2倍的S[i-1][j-1]。最终得到
\(Answer = S[i][j] - S[i][l-1] - S[k-1][j] + S[k-1][l-1]\)

标签:Arr,前缀,复杂度,元素,数组,Sum
From: https://www.cnblogs.com/CrescentWind/p/17810976.html

相关文章

  • 【进阶算法】一维数组的前缀和
    前缀和是指数组某个索引之前的所有元素的和,是一种重要的预处理手段,使用前缀和可以快速求出数组某一个区间的和。 示例:数组arr=[8,1,3,-2,5,0,-3,6],输入m个询问,每个询问输入一对l,r。对于每个询问,要求输出原数组中从第l个数到第r个数的和。比如,第1次询问,输入[0,2],需要输出1......
  • 前缀和习题汇总
    一、洛谷p1147连续自然数和题目描述对一个给定的正整数\(M\),求出所有的连续的正整数段(每一段至少有两个数),这些连续的自然数段中的全部数之和为\(M\)。例子:\(1998+1999+2000+2001+2002=10000\),所以从\(1998\)到\(2002\)的一个自然数段为\(M=10000\)的一个解。输入格......
  • 前缀和差分
    前缀和什么是前缀和:简单来说,有一个\(x\)数组和\(y\)数组,\(y\)是\(x\)的前缀和数组。\(y_1=x_1\)\(y_2=x_1+x_2\)\(y_3=x_1+x_2+x_3\)\(y_n=x_1+x_2+x_3+……+x_n\)求区间和求前缀和的公式r[i]=r[i-1]+s[i]\(r\)为前缀和数组,要求\(x\)到\(y\)的区间和的话,那么......
  • 前缀和和差分
    一维前缀和1#include<iostream>2usingnamespacestd;34constintN=100010;5intn,m;6inta[N],s[N];//初始化s[0]=078intmain()9{10scanf("%d%d",&n,&m);11for(inti=1;i<=n;i++)cin>>......
  • 14. 最长公共前缀
    目录题目法一、翻译法二、内置函数zip+set法三、排序题目编写一个函数来查找字符串数组中的最长公共前缀。如果不存在公共前缀,返回空字符串""。示例1:输入:strs=["flower","flow","flight"]输出:"fl"示例2:输入:strs=["dog","racecar","car"]......
  • Codeforces Round 904 (Div. 2) C. Medium Design(前缀和+差分)
    CodeforcesRound904(Div.2)C.MediumDesign思路:因为出现的线段应该为不相同的线段,所以最小值应该为\(1\)或\(m\)因此我们可以通过差分储存线段范围内的加值,再用前缀和表示这个范围内的最大加值sl为不包含\(1\)的线段的差分,sr为不包含\(m\)的线段差分记录用于差分的......
  • Python根据列表在指定目录寻找对应前缀的文件
    现在有一个txt列表,里面包含的是一些文件名,如a,b等等,现在需求是在一个多级文件夹下,需要寻找以a为名字的任何格式文件,如a.001,a.002等等,寻找这个txt列表里包含的文件名的对应文件,复制到指定文件夹下importosimportshutil#读取文件名列表withopen('msg.txt','r')asfile:......
  • 数据库系列:前缀索引和索引长度的取舍
    数据库系列:MySQL慢查询分析和性能优化数据库系列:MySQL索引优化总结(综合版)数据库系列:高并发下的数据字段变更数据库系列:覆盖索引和规避回表数据库系列:数据库高可用及无损扩容数据库系列:使用高区分度索引列提升性能1背景有时候我们需要在字符类型的字段上建设索引,但是如果......
  • 14. 最长公共前缀
    编写一个函数来查找字符串数组中的最长公共前缀。如果不存在公共前缀,返回空字符串""。示例1:输入:strs=["flower","flow","flight"]输出:"fl"代码1.为空,res="",不为空,res=strs[0];2.开始遍历3.s.find(res)!=0不是其前缀,开始减去res的最后一个字符classSol......
  • Python字符串前缀u、r、b、f含义
    1、字符串前加u例子:u"字符串中有中文"含义:前缀u表示该字符串是unicode编码,Python2中用,用在含有中文字符的字符串前,防止因为编码问题,导致中文出现乱码。另外一般要在文件开关标明编码方式采用utf8。Python3中,所有字符串默认都是unicode字符串。 2、字符串前加r例子:r......