523. 连续的子数组和
题目:给你一个整数数组 nums 和一个整数 k ,编写一个函数来判断该数组是否含有同时满足下述条件的连续子数组:子数组大小 至少为 2 ,且子数组元素总和为 k 的倍数。 如果存在,返回 true ;否则,返回 false 。(小坑0是任意数的倍数)
思考过程:
想法一:暴力
双层循环加判断,复杂度为O(n^3)超时。
想法二:动态规划
d[i][j]表示第i个元素到第j个元素的和,计算过程中判断。复杂度为O(n^2)超时。
想法三:前缀和 + 哈希表法
① 首先为了方便计算连续子数组的和,我们可以计算一下前缀和。如:
下标 0 1 2 3 4 [-1] 0 1 2 3 4
nums 23 2 4 6 7 preSum(前缀和) [ 0] 23 25 29 35 41
可知连续子数组[i:j]的和num[i:j] = preSum[j-1] - preSum[i-1],如:nums[2:4] = nums[2]+nums[3] = preSum[3] - preSum[1]。考虑当i等于0时候 要计算num[0:j] = preSum[j-1] - preSum[-1] 需要设置preSum[-1]=0(可在初始化时完成)。
② 知道了连续子数组的和,但是要满足两个条件:i)j-i>=2(注意nums[i:j]是左闭右开的)代表i j-1不是同一个元素 2) num[i:j] % k == 0(代表是k的倍数)。
根据条件二 num[i:j] % k == 0 则(preSum[j-1] - preSum[i-1])% k == 0 即 preSum[j-1] % k = preSum[i-1]% k,那么现在主要任务转移为计算preSum[x] % k(x的范围是-1到n-1),并判断preSum[i] %k 和 preSum[j] %k 在满足条件j-i>=2的情况下是否相等。可通过哈希表来实现:
如果不在哈希表中:
添加 preSum[x] %k为key,对应下标为value到哈希表中。
如果在哈希表中并且满足在哈希表中对应元素的下标和遍历时候的下标满足 j-i>=2的关系,则返回True。如下述情况返回true :
-1 0 1 2 3 4
preSum % k 0 2 4 1 0 6 有两个0存在,且3-(-1)>=2
ps:①初始化 preSum[-1]=0 ,可以直接添加到哈希表中
代码:
def checkSubarraySum(nums, k):
n, hs, preSum = len(nums), {0: -1}, 0
for i in range(n):
preSum += nums[i]
if (preSum % k) in hs: # 当 preSum % k 在字典里
# 如果在字典里 要满足 中间隔一个元素 即 i - hs[preSum % k] >= 2
if i - hs[preSum % k] >= 2:
return True
# 在字典里 但是不满足上述要求的 不做操作(不会添加到里边)
else: # 当 preSum % k 不在字典里
hs[preSum % k] = i
return False
自己犯的一个错误,我将条件 (preSum % k) in hs 和 i - hs[preSum % k] >= 2合并后,后边的else没变,导致犯错!!!大家写的时候要注意下
知识点:
哈希表用字典来模拟。
初始化: hs = dict() ; hs = {a:b}
添加元素: hs[c] = d
得到对应key的value: v2 = hs.get(key1,value1) (如果key1在hs中,返回对应的value,如果不在,返回value1)
路虽远,行则将至。事虽难,做则必成 。