题目描述:
给定一个整数数组 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
这道题与LeetCode
560:和为K的子数组 非常相似,只需要将if判定条件修改一下即可
Solution1:暴力破解,时间复杂度为O(N^2)
,但是在提交过程中超出时间限制
class Solution:
def subarraysDivByK(self,A,K):
'''
:type A: List[int]
:type K: int
:rtype: int
'''
count = 0
for i in range(len(A)):
sum = 0
for j in range(i,len(A)):
sum+=A[j]
if sum % K == 0:
count+=1
return count
Solution2:
既然是看有没有子数组能被能被K整除,那么我们可以设count_mod_i = (A[0] + A[1] + A[2] +·······+A[i])%K,count_mod_j = (A[0] + A[1] + A[2] +·······+A[i] + A[i+1] + ······ +A[j])%K,这里 j>i,若count_mod_j - count_mod_i=0,那么从A[i]到A[j]这子数组必然能被K整除,举个例子:
A=[4,5,0,-2,-3,1],K=5.
第一个数即A[0]=4,只算到i=0即A[0]的和,然后对K做模运算:A[0]%5=4,然后j=1,即第二个数A[1],计算A[0]到A[1]的和然后做模运算:(A[0]+A[1])%5=4,二者相等(这算一种情况),这说明A[0]到A[1]之间的子数组和即A[1]能被5整除,事实也证明:A[1]=5确实能被5整除。然后将这所有的情况(相同余数的次数)分别记录下来。假如得到余数为4的次数为1,那么单单针对这种情况的子数列的个数为1*(1-1) /2= 0,因为只出现一次这种情况(余数为4),是不符合一开始我们说的那种思想的。假如得到余数为4的次数为2,那么单单针对这种情况子数列的个数为2*(2-1)/2=1。最后将所有情况加和
代码:
import collections
class Solution:
def subarraysDivByK(self,A,K):
'''
:param A: list[int]
:param K: int
:return: int
'''
count_mod = [0]
for num in A:
count_mod.append((count_mod[-1]+num) % K)
count = collections.Counter(count_mod)
return sum((v-1)*v/2 for v in count.values())