算法练习Day10 [LeetCode]974. 和可被 K 整除的子数组

974. 和可被 K 整除的子数组

给定一个整数数组 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. 1 <= A.length <= 30000
2. -10000 <= A[i] <= 10000
3. 2 <= K <= 10000


利用前缀和 + 哈希表的思路
设置一个以前缀和模 K后 的值为键,出现次数为值的哈希表 record,在遍历的同时进行更新,从排列组合的角度考虑子数组个数。注意的一个边界条件是,我们需要对哈希表初始化,记录record[0]=1,这样就考虑了前缀和本身被 K整除的情况。

举例说明
A = [4,5,0,-2,-3,1],K=5
前缀和 P = [4,9,9,7,4,5]
前缀和对K = 5取模 M = [4,4,4,2,4,0]
4对5取模等于4, 4加上一个数对5取模还等于4,说明什么?说明加上的这个数能被5整除。
M[0]和M[1]都等于4,说明A[1]这个数能被5整除。
M[0]和M[2]都等于4,说明A[1]+A[2]这个数能被5整除。
M[0]和M[4]都等于4,说明A[1]+A[2]+A[3]+A[4]这个数能被5整除。
M[1]和M[2]都等于4,说明A[2]这个数能被5整除。
M[1]和M[4]都等于4,说明A[2]+A[3]+A[4]这个数能被5整除。
M[2]和M[4]都等于4,说明A[3]+A[4]这个数这个数能被5整除。
则M中如果有4个4,说明A中有3+2+1个数可以被5整除。也就是4*(4-1)/2 个数可以被5整除。
推广开来,如果M中有m个x,说明A中有m*(m-1)/2个数可以被K整除。
特别地,如果M中有n个0,结果还要加上n,变为n + m*(m-1)/2。因为比如M[0]和M[1]都等于0,说明A[0]和A[1]都能被K整除。

class Solution {
    public int subarraysDivByK(int[] A, int K) {
        Map<Integer, Integer> record = new HashMap<>();
        record.put(0, 1);
        int sum = 0;
        for (int elem: A) {
            sum += elem;
            // 注意 Java 取模的特殊性,当被除数为负数时取模结果为负数,需要纠正
            int modulus = (sum % K + K) % K;
            record.put(modulus, record.getOrDefault(modulus, 0) + 1);
            //getOrDefault(key,defaultValue)方法:当Map集合中有这个key时,就使用这个key值,如果没有就使用默认值defaultValue
        }

        int ans = 0;
        //通过Map.entrySet遍历key和value
        for (Map.Entry<Integer, Integer> entry: record.entrySet()) {
            ans += entry.getValue() * (entry.getValue() - 1) / 2;
        }
        return ans;
    }
}
上一篇:day10-注解跟反射(Annotation)


下一篇:day10-栈