【优选算法】Prefix-Kage:前缀和的算法影(下)
前缀和+后缀和
寻找数组的中心下标
✏️题目描述:
✏️示例:
传送门:寻找数组的中心下标
题解:
💻第一步: 要计算前后和相等
的数的下标(不包括该数),显然要计算前后缀和
假设符合题意的数的下标为 i
,那么其前后数的下标就很容易推导出来了。我们小学的时候就学过函数,那么前后和是不是也可以用一个函数表示
,只要有符合的 i 直接代入即可
f:前缀和数组 →
f[i]
表示:[0,i-1]
区间所有元素的和
g:后缀和数组 →g[i]
表示:[i+1,n-1]
区间所有元素的和
所以根据一维前缀和模版的公式
可得 f[i] = f[i - 1] + nums[i - 1]
、g[i] = g[i + 1] + nums[i + 1]
,注意这个后缀和是从后往前加
推导的
💻第二步:
接着遍历题目的数组
,枚举出符合 f[i] == g[i]
情况的下标就行了
💻细节问题:
根据我们写的两个公式,当 i = 0
,i = n - 1
时,即第一个数和最后一个数的下标
,发现会出现 f[-1]
、g[n]
的情况,也就是数组越界
,所以前缀和
要从第二个数开始
,后缀和
要从倒数第二个数开始
,那么第一个数和最后一个数会不会访问不到?
答案是不会的
,后缀和
会访问到第一个数
,前缀和
会访问到最后一个数
。因此当 i
在最左侧
或最右侧
时,令 f[0]
为 0
,g[n-1]
为 0
来处理这种特殊情况
💻代码实现:
1 |
|
如果数组存在
中心下标,返回 1
;不存在
中心下标,返回 -1
除自身以外数组的乘积
✏️题目描述:
✏️示例:
传送门:除自身以外数组的乘积
题解:
💻细节问题:
本题和寻找数组的中心下标
思路基本一致,因为要相乘,所以令 f[0] = 1
,g[n-1] = 1
,要额外创建一个数组
存放各个位置下乘积的结果
💻代码实现:
1 |
|
前缀和+哈希表
和为k的子数组
✏️题目描述:
✏️示例:
传送门:和为k的子数组
题解:
💻第一步:
根据题意要求和为k的子数组
,那么假设在某个下标为 i 处
有符合题意的子数组
,前缀和
为 sum
表示
那么就有 sum[i] - sum[j] = k
,移项
可得 sum[i] - k = sum[j]
,所以要求和为 k 的子数组
等同于在不断往前求前缀和 sum[i] 的过程中
,计算 sum[i] - k
能否找到符合题意的 sum[j]
💻第二步:
因为前缀和可能存在重复的情况
,我们又需要计算前缀和其对饮出现的次数
,进而我们可以想到哈希表
来处理这种情况
💻细节问题:
🚩前缀和加入哈希表的时机?
在不断往前求
前缀和 sum[i]
的过程中,i 是不断变化的,我们是要找在[0,i-1] 区间
内,有多少个前缀和等于 sum[i] - k
,我们关心的是sum[i]-k 是否在之前出现过
,以及出现的次数
,这样就能知道有多少个子数组的和为 k
• 如果一次性把每个位置的前缀和都放入哈希表,会导致一些问题。例如,当有一个数组nums = [1,2,3],k = 3
• 假设我们在遍历过程中,不加判断地每次都放入哈希表。当第一次计算到前缀和为3(1 + 2)
时放入哈希表,然后继续遍历到3这个元素时,前缀和变成了6
,如果此时又放入哈希表,就会覆盖之前前缀和为3的记录
• 但是,从1开始到2的子数组和为3
,从3本身这个元素也构成和为3的子数组,这两个情况是不同的,如果错误地覆盖了之前的记录,就无法正确统计出和为k的子数组数量
🚩不用真的创建一个前缀和数组
用一个
变量sum
来标记前一个位置的前缀和即可
🚩如果整个前缀和等于k呢?
那么就每次遍历开始前特殊的令
hash[0] = 1
💻代码实现:
1 |
|
和可被k整除的子数组
✏️题目描述:
✏️示例:
传送门:和可被k整除的子数组
题解:
💻细节问题:
本题基本上与和为k的子数组
思路一致
补充两个知识点:
- 同余定理
- 负数结果修正成正数
因为数组里可能会存在负数
,而数组下标没有负数
,所以需要修正
所以根据同余定理
,这里本质上就是在求在[0,i-1]区间
内,有多少个前缀和的余数等于 sum % k
💻代码实现:
1 |
|
连续数组
✏️题目描述:
✏️示例:
传送门:连续数组
题解:
💻细节问题:
该题的思路也是前缀和+哈希表
,要求和为有相同数量的 0 和 1
,不妨令所有的 0 为 -1
,也就把题目转化为 sum[i] - sum[j] = 0
,即 sum[i] = sum[j]
,求在遍历前缀和的过程中能不能找到前面的一个前缀和与其相等
,注意 hash[0] = -1
如果在后面又求到一个符合sum[i] = sum[j]
的怎么办?
本题求的是
最长连续子数组
,所以两个是同种情况
,无需考虑覆不覆盖的问题,无论哪个都可以
💻代码实现:
1 |
|
二维前缀和拓展
矩阵区域和
✏️题目描述:
✏️示例:
传送门:矩阵区域和
💻解读题意:
这题单看题目或许有点难理解,以示例 1 为例
,每个方格里的数对应的求和矩阵,为该方格周围延伸 k 长度所围成的数字加和(若超出范围外,则数组外的不算)
。比如 2
的矩阵求和
为 1 + 2 + 3 + 4 + 5 + 6 = 21
,5
的矩阵求和
为 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 = 45
,求和包括原本的数
💻第一步:
本题是二维前缀和模版的延伸
,所以要用到上一篇的两个公式
传送门:【模版】前缀和(二维)
根据题意我们可以延伸该方格周围 k 长度
,若超出范围
,则让他回到边界上
,使用 max
和 min
就能解决
💻第二步:
这也是最重要的一步,因为 dp 的下标
是从 1
开始读入数据,mat 和 ans 的下标
是从 0
开始读入数据的, 为了能使用同一个公式表示来计算
,就需要进行函数映射
的操作
映射关系如图所示
💻代码实现:
1 |
|
以上就是所有精选的前缀和算法题解析,多写几遍代码,不要死套模版,灵活理解应用能够更好地掌握前缀和算法,整理不易,如有出错希望能够私信博主指出错误!😎