给定一个整数数组 A,返回其中元素之和可被 K 整除的(连续、非空)子数组的数目。
示例:
输入:A = [4,5,0,-2,-3,1], K = 5
输出:7
解释:
有 7 个子数组满足其元素之和可被 K = 5 整除:
[4, 5, 0, -2, -3, 1], [5], [5, 0], [5, 0, -2, -3], [0], [0, -2, -3], [-2, -3]
提示:
1 <= A.length <= 30000
-10000 <= A[i] <= 10000
2 <= K <= 10000
解题思路
通常,涉及连续子数组问题的时候,我们使用前缀和来解决它们。连续子数组的和就可以表示为前缀和的差,比如 sum(A[i : j + 1]) = s[j + 1] - s[i]。
**定义前缀和数组长度时最前面添加一个为0的项,为了包含前缀和刚好为K的倍数的情况。**因为取模的时候要作差来求,如果前缀和中刚好有一个为k的倍数,所以这个数减去添加的0刚好还是能整除k。
同余定理:如果(a-b)/k为整数,则称a和b对整数k同余(即余数相同)
最后,从余数相同的数里取出两个进行组合,得到的总的组合方式就是结果。
组合公式:
class Solution(object):
def subarraysDivByK(self, A, K):
"""
:type A: List[int]
:type K: int
:rtype: int
"""
# 求连续数组的和,连续数组的和可以表示为前缀和的差,比如 sum(A[i : j + 1]) = s[j + 1] - s[i]
s = [0] * (len(A) + 1) # s表示前缀和,长度为len(A) + 1),为了包含前缀和刚好为k的倍数的情况
kcnt = [0] * K # kcnt[i]代表s中有多少个元素 mod K 为i,索引代表余数值,数值表示余数为i的个数
# 求前缀和
for i in range(len(A)):
s[i + 1] = s[i] + A[i]
# 如果(a-b)/k为整数,则称a和b对整数k同余(即余数相同)
for item in s:
kcnt[item % K] += 1
# 两个前缀和余数相同,说明他们的差能够整数k,即他们之间的子数组和能够整数k
# 使用组合公式计算
return sum(x * (x - 1) // 2 for x in kcnt)