哈希表:使用哈希表存储,以前缀和模 K 的值为键,其值出现的次数为值。在遍历数组的同时更新。我们需要对哈希表初始化,即余数为 0 出现的次数为 1 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
classSolution{ publicintsubarraysDivByK(int[] A, int K){ Map<Integer, Integer> record = new HashMap<>(); int sum = 0, ans = 0; //初始化 record.put(0,1); for(int e : A){ sum += e; //Java 负数取模产生负数,需要纠正 int mod = (sum % K + K) % K; //得到前缀和模 K 的值出现的次数 int times = record.getOrDefault(mod, 0); //更新结果和以 mod 为余数的前缀和出现的次数 ans += times; record.put(mod, times + 1); } return ans; } }
时间复杂度 O(n) 遍历一次数组,空间复杂度 O( min (n, k) ) 模 k 得到的余数最多有 k 个。
我们还可以先生成哈希表,得到前缀和模 k 的值出现的次数 n,对于这个值,和可被 k 整除的子数组的个数为 n(n-1)/2,类似于冒泡排序的两两比较。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
classSolution{ publicintsubarraysDivByK(int[] A, int K){ Map<Integer, Integer> record = new HashMap<>(); int sum = 0, ans = 0; record.put(0,1); for(int e : A){ sum += e; //Java 负数取模产生负数,需要纠正 int mod = (sum % K + K) % K; record.put(mod, record.getOrDefault(mod, 0) + 1); } for(Map.Entry<Integer, Integer> entry : record.entrySet()){ ans += entry.getValue() * (entry.getValue() - 1) / 2; } return ans; } }