给定一个整数数组 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
由于数据比较庞大,暴力O(n^2)是行不通的
举例 对于A= [4,5,0,-2,-3,1] K = 5,
前缀和 s = [0, 4, 9, 9, 7, 4, 5] ,然后对每一项取模,得到[0, 4 ,4, 4, 2, 4, 0], 对于K,存在的模从0 ~ K-1。
构件K个元素的数组,索引表示模,值表示模的数量{ 模 : 数量 }
kcnt = [2, 0, 1, 0, 4] 代表在s中有2个元素的模都为0(即0和5),0个元素的模为1, 1个元素的模为2(即7),0个元素的模为3,4个元素的模为4(即4,9,9,4)
先拉出来[4, 9, 9, 7, 4]来看,这里4+5=9,9+0=9,9+(-2-3) = 4。先把7略过,4,9,9,4他们的模都是4,是因为相邻两者之间相加的数是5的倍数(这里可以将-2-3看做一个-5),在这同模的4个数之间任意取出两个数,那么这两个数的差一定是5的倍数,所以存在C(4, 2) = 6中子数组
所以在保证模相同的情况下,取出两个数都可以得到一组答案。对于这个例子,看kcnt,得到C(2, 2) + C(1, 2) + C(4, 2) = 1 + 0 + 6 = 7
需要注意的是负数的取模,(不是取余) 例如 -7 mod 4 = 1;
-7对4取模
-1 * 4 = -4 > -7,
-2 * 4 = -8 < -7;
-7 - (-2 * 4) = 1
class Solution {
public:
int subarraysDivByK(vector<int>& A, int K) {
int n = A.size();
if(n == 0) return 0;
vector<int> modk(K, 0);
modk[0]++;
int presum = 0; //前缀和
for(int i=0; i<n; i++){
presum += A[i];
if(presum >= 0) modk[presum % K]++;
//注意取模
else modk[(presum%K + K)%K]++;
}
int cnt = 0;
//C(n, 2);
for(int i=0; i<K; i++){
cnt += modk[i] * (modk[i]-1) / 2;
}
return cnt;
}
};