总结背景
在写CSP的时候发现有一段时间第二题非常喜欢考这个考点,在这里总结一些
前缀和
概念
- 前缀和是什么:数组该位置之前的元素之和
- 作用:快速求出数组中某段区间的和
如果每次都是遍历一遍求和那就每次都得是O(n)的复杂度,m次就得到O(mn)。如果用前缀和,那就第一遍用O(n)的复杂度遍历求出前缀和,然后每次求的的时候只需要区间首位作差即可,这个时候每次复杂度就降到O(1)啦
- 所以在说方法之前在强调一下使用场景:
一般经常需要求一个连续区间的和的时候常常使用前缀和来提高效率
方法
一维数组的前缀和
求一维数组a中(l,r)区间的和,可以首先求出前缀和数组s,然后使用s[r]-s[l-1]可以快速求出区间的和
- 求前缀和公式:s[i]=s[i-1]+a[i]
- 求区间(l,r)的和公式:区间和m=s[r]-s[l-1]
a = [0]+list(map(int,input().split()))
s = [0]*n
# 这里从0开始,但是一般可以使数组从1开始,这样可以简化计算
for i in range(1,n):
s[i] = s[i-1]+a[i]
# 求区间范围
def get_part_sum(l,r):
return s[r]-s[l-1]
二维数组的前缀和
CSP大多用的是一维数组,二维数组的使用和一维数组类似,这里就先不写二维数组啦
差分数组
差分数组在一定程度上是前缀和的逆运算
差分数组实际上就是记住当前数据相对于前一个数据的变化量,这样如果要对一个区间内所有的数据都加或减相同的数时,只需要对始末进行处理,而不需要每次处理都要遍历数组,只在最后求结果时遍历一次输出即可
用代码理解一下:
# a:原数组
# b:差分数组
b[1] = a[1]
for i in range(2,n):
b[i] = a[i]-a[i-1]
核心操作:
将区间(l,r)全部加上C,等价于:b[l]+=C, b[r+1]-=C
理解:区间的开头b[l]加上C后,求区间里每一个数时从区间开始处进行累加,此时每一个数都加了C;然而+C只进行到了b[r],b[r+1]没有进行+C操作,累加到r+1时还会加C,所以要在r+1处进行-C操作
来段代码理解一下:
# a:原始数组
# b:差分数组
def create_b():
for i in range(1,n+1):
b[i] = a[i]-a[i-1]
return b
def edit_arr(l,r,c):
b[l]+=c
b[r+1]-=c
def get_new_num(index):
new_num = 0
for i in range(1,index):
new_num += b[i]
return new_num
例题
CSP
202203-4 出行计划
201312-3 最大的矩形
202109-2 非零段划分
leetcode
这里还没有具体做,先参考一下大佬的记录吧