前缀和与差分

本文介绍了前缀和的概念,包括一维和二维前缀和,并提供了LeetCode练习题作为实例。一维前缀和是数组前n项的和,二维前缀和涉及矩阵的累加和。差分是前缀和的逆运算,常用于区间加法操作。文章通过具体例子展示了差分在解决LeetCode问题中的应用。
摘要由CSDN通过智能技术生成

B站视频:https://www.bilibili.com/video/BV1r4411k7dL?spm_id_from=333.337.search-card.all.click

前缀和

前缀和是一种重要的预处理,能大大降低查询的时间复杂度。可以简单理解为“数列的前n项的和”。根据数组的维度,前缀和有一维前缀和和二维/多维前缀和。

一维前缀和

一维前缀和就是一维数组前n项的和。求解一维前缀和递推公式如下:
s u m [ i ] = { a [ 0 ] , i=0 s u m [ i − 1 ] + a [ i ] , i>0 sum[i] = \begin{cases} a[0], & \text{i=0} \\ sum[i-1]+a[i], & \text{i>0} \end{cases} sum[i]={a[0],sum[i1]+a[i],i=0i>0
当我们求出前缀和数组后,我们可以使用O(1)的时间复杂度求出区间[q1, q2]的区间和:

interval[q1, q2] = sum[q2] - sum[q1 - 1]

求解前缀和数组的java代码如下:

int[] sum = new int[nums.length];
sum[0] = nums[0];
for (int i = 1; i < nums.length; i++) {
    sum[i] = sum[i - 1] + nums[i];
}

有的地方会设置前缀和数组第0项sum[0]=0,递归公式为sum[i]=sum[i-1]+a[i-1]

int[] sum2 = new int[nums.length + 1];
for (int i = 0; i < nums.length; i++) {
    sum2[i + 1] = sum[i] + nums[i];
}
LeetCode练习题

560. 和为 K 的子数组

523. 连续的子数组和

974. 和可被 K 整除的子数组

二维前缀和

二维前缀和就是二维数组的前缀和,sum[i][j]为上顶点(0, 0)到下顶点(i, j)组成矩阵的各项和:
在这里插入图片描述

二维前缀和的递推公式如下:
s u m [ i ] [ j ] = { a [ 0 ] [ 0 ] , i=0, j=0 s u m [ 0 ] [ j − 1 ] + a [ 0 ] [ j ] , i=0, j>0 s u m [ i − 1 ] [ 0 ] + a [ i ] [ 0 ] , i>0, j=0 s u m [ i − 1 ] [ j ] + s u m [ i ] [ j − 1 ] − s u m [ i − 1 ] [ j − 1 ] + a [ i ] [ j ] , i>0, j>0 sum[i][j] = \begin{cases} a[0][0], & \text{i=0, j=0} \\ sum[0][j-1]+a[0][j], & \text{i=0, j>0} \\ sum[i-1][0]+a[i][0], & \text{i>0, j=0} \\ sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+a[i][j], & \text{i>0, j>0} \end{cases} sum[i][j]=a[0][0],sum[0][j1]+a[0][j],sum[i1][0]+a[i][0],sum[i1][j]+sum[i][j1]sum[i1][j1]+a[i][j],i=0, j=0i=0, j>0i>0, j=0i>0, j>0
图中红色区间sum[i-1][j-1]为重复加的部分,因此需要减去。

当我们求出二维数组的前缀和后,同样可以使用O(1)的时间复杂度求出区间[(q1, q2), (q3, q4)]的各项和:
在这里插入图片描述

interval[(q1, q2), (q3, q4)] = sum[q3][q4] - sum[q1 - 1][q4] - sum[q3][q2 - 1] + sum[q1 - 1][q2 - 1]
LeetCode练习

304. 二维区域和检索 - 矩阵不可变

差分

差分和前缀和可以说是一对“好基友”,差分是前缀和的逆运算,如果存在原数组a[i],那么对差分数组求前缀和就是原数组
d [ i ] = { a [ 0 ] , i=0 a [ i ] − a [ i − 1 ] , i>0 d[i] = \begin{cases} a[0], & \text{i=0} \\ a[i]-a[i-1], & \text{i>0} \end{cases} d[i]={a[0],a[i]a[i1],i=0i>0
一维差分一般用于这样的场景:多次对序列的某个区间加上一个数,并在最后询问序列是什么样的。如LeetCode1094题 拼车。这类题目一般会先对序列求出差分数组,如果题目要求原数组区间[q1, q2)+ 2,那么差分数组只需要操作下面两步:

d[q1]=d[q1]+2;
d[q2]=d[q2]-2;

操作完成后对差分数组求前缀和就能把原数组还原回来。

LeetCode练习题

1094. 拼车

1109. 航班预订统计

121. 买卖股票的最佳时机

122. 买卖股票的最佳时机 II

2132. 用邮票贴满网格图

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值