和可被 K 整除的子数组

在这里插入图片描述

题解

知识点

通常,涉及连续子数组问题的时候,我们使用前缀和来解决。
我们令 P[i] = A[0] + A[1] + … + A[i]。那么每个连续子数组的和 s u m ( i , j ) = P [ j ] − P [ i − 1 ]    ( 其 中 0 < i < j ) sum(i, j) = P[j] - P[i-1] \;(其中0 < i < j) sum(i,j)=P[j]P[i1](0<i<j), 判断连续子数组的和能否被 K 整除就等价于 ( P [ j ] − P [ i − 1 ] )   m o d   K = = 0 ) (P[j] - P[i-1])\, mod\, K == 0) (P[j]P[i1])modK==0), 根据同余定理 ,只要 P [ j ]   m o d   K = = P [ i − 1 ]   m o d   K P[j] \,mod \,K == P[i-1]\, mod\, K P[j]modK==P[i1]modK, 就可以满足条件。

方法一:哈希表+逐一统计

思路

对数组进行遍历,在遍历的同时统计答案。当遍历数组的第 i 个元素时,统计数组以 i 结尾符合条件的子数组的个数。我们维护一个以前缀和 mod K 的值为键,出现次数为值的哈希表 r e c o r d record record,在遍历的同时更新哈希表。那么以 i 结尾的符合条件的子数组个数即为 r e c o r d [ P [ i ]   m o d   K ] record[P[i] \,mod\, K] record[P[i]modK]

Code

cpp

class Solution {
public:
    int subarraysDivByK(vector<int>& A, int K) {
        unordered_map<int, int> record = {{0, 1}};
        int ans = 0; int sum = 0;
        for (int i: A){
            sum = sum + i;
            int modulus = (sum%K + K) % K;
            if (record.count(modulus)){
                ans = ans + record[modulus];
            }
            record[modulus]++;
        }
        return ans;
    }
};

python

class Solution:
    def subarraysDivByK(self, A: List[int], K: int) -> int:
        
        record = {0: 1}
        sum_fro, ans = 0, 0
        for i in A:
            sum_fro += i

            modulus = sum_fro % K
            nums = record.get(modulus, 0)
            ans += nums

            record[modulus] = nums + 1

        return ans

方法二:哈希表 + 单次统计

思路

依据方法一中的思路,在遍历数组时只维护哈希表。在遍历结束后,我们遍历哈希表,从排列组合的角度统计答案。
对于哈希表中的每个键值对 ( x , v x ) (x, v_x) (x,vx),它表示前缀和 mod K 的值 x x x 出现了 v x v_x vx次。那么这些满足条件的位置两两之间都可以构成 被 K 整除的连续子数组,数量为 ( v x 2 ) = v x ∗ ( v x − 1 ) 2 \begin{pmatrix}v_x\\2\end{pmatrix} = \dfrac{v_x * (v_x-1)}{2} (vx2)=2vx(vx1) 个可被 K 整除的连续子数组。

Code

cpp

class Solution {
public:
    int subarraysDivByK(vector<int>& A, int K) {
        unordered_map<int, int> record = {{0, 1}};
        int ans = 0; int sum = 0;
        for (int i: A){
            sum = sum + i;
            int modulus = (sum%K + K) % K;
            record[modulus]++;
        }

        for (auto [x, vx]: record){
            ans = ans + vx * (vx - 1) / 2;
        }
        return ans;
    }
};

python

class Solution:
    def subarraysDivByK(self, A: List[int], K: int) -> int:
        
        record = {0: 1}
        sum_fro, ans = 0, 0
        for i in A:
            sum_fro += i

            modulus = sum_fro % K
            record[modulus] = record.get(modulus, 0) + 1
        
        for x, vx in record.items():
            ans += vx * (vx - 1) // 2
        
        return ans

参考:

  1. 和可被K整除的子数组
  2. 又见【前缀和】| 含 mod 运算的详细推导
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值