前缀和 之 哈希表 之 和 的奇偶与倍数
文章目录
- 930.和相同的二元子数组
- 523.连续的子数组和
- 求解连续子数组的和的问题,常常会使用到这个
前缀和
的思路,当然当数组存在单调性的时候,可以考虑使用不定长滑动窗口
,在这里解释一下,何为数组的和存在这个单调性?
就是nums[i]>=0
或者nums[i]<=0
,就是最终这个窗口的和值是随着窗口的大小变大而窗口的和值是随着变大或者变小的
- 当然,前缀和更能处理这种
非单调性
的问题,当出现子数组的和
的某种性质的统计或者判断的时候,我们常常会使用到哈希表
进行对应的存储
930.和相同的二元子数组
930.和相同的二元子数组
- 这个题目有多种解法,由于存在这个
nums[i]>=0
,所以是存在这个单调性的问题,所以考虑使用滑动窗口,当然,由于这个是恰好型的问题,所以考虑使用两个至少型的计算进行转化
class Solution:
# 定义嵌套方法,并不使用 self参数
def numSub(self,nums:List[int],goal:int ) ->int :
left = count = ans = 0
for right,i in enumerate(nums):
count+=i
while count >= goal and left <= right:
count-=nums[left]
left+=1
ans += left
return ans
def numSubarraysWithSum(self, nums: List[int], goal: int) -> int:
# 打算使用越长越好的方法,求解出和 >= goal 和 >= goal+1的情况
return self.numSub(nums,goal) - self.numSub(nums,goal+1)
- 更加通用的方法是,使用这个
前缀和+哈希表
,对于子数组的和为goal
,我们只需使用哈希表存储对应的前缀和的次数
,对于子数组的和为goal
,只需查询当前的cusum-goal
是否存在哈希表中,如果存在,则加上对应的次数,最后再更新这个前缀出现的次数即可
from collections import defaultdict
class Solution:
def numSubarraysWithSum(self, nums: List[int], goal: int) -> int:
n = len(nums)
# 子数组要求是和为goal的子数组的数目,我们只需不断累加,记录对应的累加和的出现次数
cursum = 0
store = defaultdict(int)
store[0] += 1
ans = 0
for i,c in enumerate(nums):
cursum += c
if cursum - goal in store:
ans += store[cursum-goal]
store[cursum]+=1
return ans
523.连续的子数组和
523.连续的子数组和
- 倍数的问题,就不是单纯存储这个
前缀和
的出现的次数了,仔细想想,得存储这个%k
的余数的情况,因为两个同余数的前缀和作差,那么该子数组的和肯定是k的倍数
,由于考虑的是长度问题,所以哈希表记录的是余数出现的位置的下标
class Solution:
def checkSubarraySum(self, nums: List[int], k: int) -> bool:
# 字典用于存储余数及其对应的索引,初始化为 {0: -1} 以处理从索引0开始的子数组
remainder_dict = {0: -1}
cumulative_sum = 0 # 累加和
# 遍历数组中的每个元素
for i, num in enumerate(nums):
cumulative_sum += num # 更新累加和
rem = cumulative_sum % k # 计算当前累加和对k的余数
# 如果余数已经存在于字典中
if rem in remainder_dict:
# 检查当前子数组的长度是否至少为2
if i - remainder_dict[rem] >= 2:
return True
else:
# 如果余数不存在,则记录当前余数对应的索引
remainder_dict[rem] = i
# 如果没有找到符合条件的子数组,返回False
return False