0021和可被K整除的子数组

和可被K整除的子数组

编号:0021

试题来源:leetcode

文章目录

  • 题目描述
  • 解答算法
    • 逐一统计
      • 算法思路
      • 代码实现
      • 复杂度分析

题目描述

给定一个整数数组A,返回其中元素之和可被K整除的(连续、非空)子数组的数目

  • 1 ≤ A . l e n g t h ≤ 30000 1\leq A.length\leq 30000 1A.length30000
  • − 10000 ≤ A [ i ] ≤ 10000 -10000\leq A[i]\leq 10000 10000A[i]10000
  • 2 ≤ K ≤ 10000 2\leq K\leq 10000 2K10000

解答算法

逐一统计

算法思路

假设存在数组P[i],记录的是从 A [ 0 … i ] A[0\dots i] A[0i]的数组和,那么要判断从 A [ i ] A[i] A[i] A [ j ] A[j] A[j]的子数组是否符合要求,只要 P [ j ] − P [ i − 1 ] P[j]-P[i-1] P[j]P[i1]可以被 K K K整除就可以,也就是说只要 P [ j ] % K = = P [ i − 1 ] % K P[j]\%K == P[i-1] \%K P[j]%K==P[i1]%K,就可以了,因此可以用一个hash_map存放 P [ i ] P[i]%K P[i],这样当遍历到P[j]的时候,只要去哈希表中进行查找,如果 P [ j ] % K P[j]\%K P[j]%K已经存在的话,那么就会有该余数对应的times的子数组满足要求;而且又多了一个 P [ i ] P[i] P[i]满足这样的余数,因此++hash_map[count]

代码实现

class Solution {
public:
    int subarraysDivByK(vector<int>& A, int K) {
        unordered_map<int, int> record = { {0, 1} };  //存放余数对应的出现次数,注意初始化余数为0的出现次数为1
        int sum = 0, ans = 0;   //sum为遍历到i的P[i],ans就是子数组个数
        for (int elem : A) {
            sum += elem;   //首先更新sum
            int modulus = (sum % K + K) % K;  //取当前sum的余数,注意这里确保了取得的余数一定是整数
            if (record.count(modulus)) {  //如果该余数已经存在,那么添加已经存在的次数进ans
                ans += record[modulus];
            }
            ++record[modulus];  //该余数又多出现了一次
        }
        return ans;
    }
};

复杂度分析

  • 时间复杂度: O ( n ) O(n) O(n),整个过程中只对数组A进行了一遍遍历
  • 空间复杂度: O ( m i n ( m , n ) ) O(min(m,n)) O(min(m,n)),其中n是A的长度,m是K的大小

你可能感兴趣的:(每天一道算法题,leetcode,数据结构,算法)