#前缀和 大概就是使用哈希表或字典的键统计前缀和 值统计前缀和的位置或个数
#求个数用for i in s:
#求长度用for i in cnt: 需要初始化cnt[0]=-1 都是键是同一个 用值相减
"""
给你一个整数数组 nums 和一个整数 k ,请你统计并返回 该数组中和为 k 的子数组的个数 。
子数组是数组中元素的连续非空序列。
"""
#前缀和之差为k 那么子数组之和即为k 前缀和x-y=k 已有x 表示y=x-k
#在哈希表中找x-k 若有则说明前缀和之差为k
#哈希表 键 前缀和 值 相同前缀和的个数
from collections import defaultdict
from typing import List
class Solution:
def subarraySum(self, nums: List[int], k: int) -> int:
#整数数组有负数 求和不能用滑动窗口 因为不能保证和一直是增大
s = [0] * (len(nums) + 1) #前缀和 两个之间的差是k时就是一种情况
for i,x in enumerate(nums):
s [i + 1] = s[i] + x
cnt = defaultdict(int) #哈希表
n = 0
for i in s: #s是前缀和的列表
n += cnt[i - k] #在哈希表中找是否有i-k 如果有说明存在两个前缀和的差为k
#你可以检查 i - k 是否已经出现过。如果出现过,说明从某个位置到当前位置的子数组和为 k
cnt[i] += 1
return n
"""
给定一个整数数组 nums 和一个整数 k ,返回其中元素之和可被 k 整除的非空 子数组 的数目。
子数组 是数组中 连续 的部分。
"""
#子数组之和可被k整除 前缀和之差为子数组之和 那么前缀和之差可被k整除 (x-y)%k==0
#已有x 表示y x%k==y%k 如上可知前缀和对k取余相同 则说明前缀和之差可被k整除
#统计前缀和对k取余后相等的个数
#哈希表 键 前缀和对k取余的结果 值 相同余数的个数
class Solution:
def subarraysDivByK(self, nums: List[int], k: int) -> int:
#子数组之和可被k整除的非空子数组数目
#依然不能滑动窗口
#两个前缀和之差能够被k整除 (x-y)%k==0
#这个式子还可以写成 x%k == y%k 就是找前缀和对k取余相等的个数
s = [0] * (len(nums) + 1)
cnt = defaultdict(int)
ans = 0
for i, x in enumerate(nums):
s[i + 1] = s[i] + x
for i in s:
a = i % k #都行 加k是为了防止余数是负数 调整成正数
ans += cnt[a]
cnt[a] += 1
return ans
"""
给定一个二进制数组 nums , 找到含有相同数量的 0 和 1 的最长连续子数组,并返回该子数组的长度。
"""
#数组中的元素只分成两类 那么一类为1 另一类为0
#转换为子数组的和为0 那么前缀和之差也为0 x-y=0 那么y=x 找前缀和相同的值
#该题求长度长度 因此哈希表的值存储的是前缀和的位置 键 前缀和
class Solution:
def findMaxLength(self, nums: List[int]) -> int:
cnt = defaultdict(int)
cnt[0] = -1
s = 0
ans = 0
for i, x in enumerate(nums):
if x == 1:
s += 1
else:
s -= 1
if s in cnt: #s是前缀和 s在哈希表中是键
ans = max(ans, i - cnt[s])
else:
cnt[s] = i #把第一次出现该前缀和的位置存到值中
return ans
"""
给你一个整数数组 nums 和一个整数 k ,
如果 nums 有一个 好的子数组 返回 true ,否则返回 false:
一个 好的子数组 是: 长度 至少为 2 ,且子数组元素总和为 k 的倍数。
注意:子数组 是数组中 连续 的部分。
如果存在一个整数 n ,令整数 x 符合 x = n * k ,则称 x 是 k 的一个倍数。
0 始终 视为 k 的一个倍数。
"""
#子数组之和为k的倍数 前缀和之差也为k的倍数 即为前缀和之差可被k整除 长度用前缀和的位置相减来表示
#(x-y)%k==0 已有x 表示y x%k==y%k 如上可知前缀和对k取余相同
class Solution:
def checkSubarraySum(self, nums: List[int], k: int) -> bool:
cnt = defaultdict(int)
cnt[0] = -1 #索引
s = 0
for i, x in enumerate(nums):
s += x #前缀和
a = s % k
if a < 0:
a = a + k #使等效的余数归到一类
if a in cnt:
if i - cnt[a] >= 2:
return True
else:
cnt[a] = i
return False
"""
给你一个长度为 n 的数组 nums 和一个 正 整数 k 。
如果 nums 的一个子数组中,第一个元素和最后一个元素 差的绝对值恰好为 k ,我们称这个子数组为好的。
换句话说,如果子数组 nums[i..j] 满足 |nums[i] - nums[j]| == k ,
那么它是一个好子数组。
请你返回 nums 中 好子数组的最大和,如果没有好子数组,返回 0 。
"""
#子数组的第一个元素和最后一个元素的差的绝对值为k
#|a[i]-a[j]|=k 即为 a[i]=a[j]+k 或 a[i]=a[j]-k
#求的是好子数组的最大和 还是前缀和之差最大 x-y 最大 那么y 最小
#s[j+1]-s[i] 最大 s[i] 最小
#与位置长度无关 不用管他长还是短 只考虑前缀和的大小 不考虑前缀和的位置
from collections import defaultdict
from math import inf
from typing import List
class Solution:
def maximumSubarraySum(self, nums: List[int], k: int) -> int:
# 哈希表,记录每个数字对应的最小前缀和
cnt = defaultdict(lambda: inf)
m = -inf # 初始化最大和为负无穷
s = 0 # 当前前缀和
for i in nums:
# 检查是否存在满足条件的子数组
# 条件:|nums[j] - nums[i]| = k,即 nums[j] = nums[i] + k 或 nums[j] = nums[i] - k
if (i - k) in cnt:
m = max(m, s + i - cnt[i - k])
if (i + k) in cnt:
m = max(m, s + i - cnt[i + k])
# 更新当前数字对应的最小前缀和
cnt[i] = min(cnt[i], s)
# 更新前缀和
s += i
# 如果没有任何满足条件的子数组,返回 0
return m if m > -inf else 0
前缀和-哈希表
最新推荐文章于 2025-12-09 14:04:42 发布
606

被折叠的 条评论
为什么被折叠?



