暴力法
计算数组前缀和,使用前缀和遍历数组连续区间。
class Solution {
public int subarraysDivByK(int[] A, int K) {
int count = 0;
int[] sum = new int[A.length + 1];
//计算前缀之和
for(int i = 1; i < sum.length; i++){
sum[i] = sum[i-1] + A[i-1];
}
//遍历所有区间,计算i-j之间的元素之和
for(int i = 0; i < sum.length; i++){
for(int j = i+1; j < sum.length; j++){
if((sum[j] - sum[i])%K == 0) ++count;
}
}
return count;
}
}
哈希表逐一统计
这题利用了同余定理,如果前缀和与%K余数相同则它们之间的组和一定能构成连续子数组,其和能整除K
class Solution {
public int subarraysDivByK(int[] A, int K) {
//键为前缀和%k,值为该余数出现的次数
HashMap<Integer,Integer> record = new HashMap<>();
record.put(0,1);//考虑整个数组本身的和整除k的情况
int sum = 0;//前缀和
int ans = 0;//答案
for(int num : A){
sum += num;
//java中负数模运算还是负数,因此需要修正
int mod = (sum % K + K) % K;
int same = record.getOrDefault(mod,0);
ans += same;//0 + 1 + 2 + 3 + 1,[4,5,-2,-3,1]
record.put(mod,same+1);
}
return ans;
}
}
哈希表 单次统计
上面的代码对结果进行了逐一统计计算,下面代码在维护完record表后使用排列组合对结果进行计算。
class Solution {
public int subarraysDivByK(int[] A, int K) {
//键为前缀和%k,值为该余数出现的次数
HashMap<Integer,Integer> record = new HashMap<>();
record.put(0,1);//考虑整个数组本身的和整除k的情况
int sum = 0;//前缀和
int ans = 0;
//维护record
for(int num : A){
sum += num;
//java中负数模运算还是负数,因此需要修正
int mod = (sum % K + K) % K;
record.put(mod,record.getOrDefault(mod,0)+1);
}
//使用排列组合,相同余数出现的总次数为entry.getValue,从中取两个进行组合
for(Map.Entry<Integer,Integer> entry : record.entrySet()){
ans += (entry.getValue() * (entry.getValue() - 1))/2;
}
return ans;
}
}