和可被 K 整除的子数组

118 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第28天,点击查看活动详情

题目描述

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

思路

我们按照正常人的思路走,首先你们一看到题目会想到暴力解法 那暴力解法怎么样呢?

时间复杂度O(n^3),
空间复杂度O(1).

确实空间的复杂度很小,因为他就需要一个变量就够了. 那么我们就要进行优化,这涉及到了子数组,我们考虑到前缀和的思路去优化.你可能要问为什么要考虑前缀和这个思路,咋考虑出来的? 前缀和数组:s[i]=a[1]+a[2]+a[3]+a[4]+....+a[i] 当你要计算(x,y)之间的数据和,就可以用s[y]-s[x]得出.所以就可以进行优化. 那我们来看看他的复杂度

时间复杂度O(n^2),少了一重循环(子数组里面数据的加和) 空间复杂度O(n),需要多余的数组来存储前缀和

代码如下

class Solution {
public:
    int subarraysDivByK(vector<int>& A, int K) {
        int sum=0;
        int num=0;
        int B[10000];
        B[0]=0;
        for(int i=1;i<=A.size();i++)
        {
            B[i]=B[i-1]+A[i-1];
            for(int j=0;j<i;j++)
            {
                sum=(B[i]-B[j]);
                if(sum%K==0)
                {
                    num++;
                cout<<sum<<endl;
                }
            }

        }
        return num;
    }
};

其实我贴出原因是让你们看一看前缀和如何优化的.但是他的时间复杂度太高,会导致超时所以还要优化. 我们继续优化,(B[i]-B[j])%k==0就是i到j数组满足题意的子数组,经过 同余原理 进一步变形就是B[i]%K == B[j]%k.那么我们就只用统计前缀和的取余相同的出现次数,就可以知道符合题意的子数组个数. 我们用哈希表去处理. 注意:不同的语言负数取模的值不一定相同,有的语言为负数,对于这种情况需要特殊处理。

class Solution {
public:
    int subarraysDivByK(vector<int>& A, int K) {
         unordered_map<int, int> record = {{0, 1}};
         int sum=0,ans=0;
         for(int item:A)
         {
             sum+=item;
             int num;
             // 注意 C++ 取模的特殊性,当被除数为负数时取模结果为负数,需要纠正
             num=(sum%K+K)%K;
            // cout<<num<<endl;
             if(record.count(num))
             {
                 ans+=record[num];

             }
             ++record[num];
         }
         return ans;
    }
};

如果不清楚count,请查c++API帮助文档或者问度娘.

时间复杂度:O(N),其中 N 是数组 A 的长度。我们只需要从前往后遍历一次数组,因此总时间复杂度为 O(N)。 空间复杂度:O(\min(N, K)),即哈希表需要的空间。当 N≤K 时,最多有 N个前缀和,因此哈希表中最多有 N+1 个键值对;当 N > K 时,最多有 K 个不同的余数,因此哈希表中最多有 K 个键值对。也就是说,哈希表需要的空间取决于 N 和 K 中的较小值。

好了讲的差不多了.如果还有什么不懂请评论,有不对的地方请指出.