0974. 和可被 K 整除的子数组
大约 2 分钟
---
974. 和可被 K 整除的子数组
- 标签:数组、哈希表、前缀和
- 难度:中等
题目链接
题目大意
给定一个整数数组 nums 和一个整数 k。
要求:返回其中元素之和可被 k 整除的(连续、非空)子数组的数目。
解题思路
先考虑暴力计算子数组和,外层两重循环,遍历所有连续子数组,然后最内层再计算一下子数组的和。部分代码如下:
for i in range(len(nums)):
for j in range(i + 1):
sum = countSum(i, j)这样下来时间复杂度就是 了。下一步是想办法降低时间复杂度。
先用一重循环遍历数组,计算出数组 nums 中前 i 个元素的和(前缀和),保存到一维数组 pre_sum 中,那么对于任意 [j..i] 的子数组 的和为 pre_sum[i] - pre_sum[j - 1]。这样计算子数组和的时间复杂度降为了 。总体时间复杂度为 。
由于我们只关心和为 k 出现的次数,不关心具体的解,可以使用哈希表来加速运算。
pre_sum[i] 的定义是前 i 个元素和,则 [j..i] 子数组和可以被 k 整除可以转换为:(pre_sum[i] - pre_sum[j - 1])% k == 0。再转换一下:pre_sum[i] % k == pre_sum[j - 1] % k。
所以,我们只需要统计满足 pre_sum[i] % k == pre_sum[j - 1] % k 条件的组合个数。具体做法如下:
使用 pre_sum 变量记录前缀和(代表 pre_sum[i])。使用哈希表 pre_dic 记录 pre_sum[i] % k 出现的次数。键值对为 pre_sum[i] : count。
- 从左到右遍历数组,计算当前前缀和并对
k取余,即pre_sum = (pre_sum + nums[i]) % k。- 如果
pre_sum在哈希表中,则答案个数累加上pre_dic[pre_sum]。同时pre_sum个数累加 1,即pre_dic[pre_sum] += 1。 - 如果
pre_sum不在哈希表中,则pre_sum个数记为 1,即pre_dic[pre_sum] += 1。
- 如果
- 最后输出答案个数。
代码
class Solution:
def subarraysDivByK(self, nums: List[int], k: int) -> int:
pre_sum = 0
ans = 0
nums_dict = {0: 1}
for i in range(len(nums)):
pre_sum = (pre_sum + nums[i]) % k
if pre_sum < 0:
pre_sum += k
if pre_sum in nums_dict:
ans += nums_dict[pre_sum]
nums_dict[pre_sum] += 1
else:
nums_dict[pre_sum] = 1
return ans