Arrays 可被k整除的子阵列数

Arrays 可被k整除的子阵列数,arrays,algorithm,subset-sum,Arrays,Algorithm,Subset Sum,在一次采访中,我提出了以下问题,尽管我给出了一个有效的实现,但效率还不够 数组A的一个切片是任何一对整数(p,Q),使得0≤ P≤ Q

在一次采访中,我提出了以下问题,尽管我给出了一个有效的实现,但效率还不够

数组A的一个切片是任何一对整数(p,Q),使得0≤ P≤ Q 要求我编写的函数必须返回可被K整除的切片数。预期的时间复杂度为O(max(N,K)),空间复杂度为O(K)

我的解决方案是最简单的,一个循环在另一个循环中,检查每个切片:O(n^2)

我一直在想,但我真的不知道如何在O(max(N,K))中做到这一点

它可能是的变体,但我不知道如何计算每个子阵列

编辑:数组中的元素可以是负片。以下是一个例子:

A = {4, 5, 0, -2, -3, 1}, K = 5

Function must return 7, because there are 7 subarrays which sums are divisible by 5
{4, 5, 0, -2, -3, 1}
{5}
{5, 0}
{5, 0, -2, -3}
{0}
{0, -2, -3}
{-2, -3}

因为你只对可被K整除的数感兴趣,所以你可以做K模的所有计算。 考虑累积和数组S,使得<代码> s [i]=S〔0〕+S〔1〕+…+S[i]。然后(P,Q)是一个可被K整除的切片,iff
S[P]=S[Q]
(记住我们所有的计算都是以K为模)。因此,您只需计算[0,…,K-1]的每个可能值在S中出现的次数

下面是一些伪代码:

B = new array( K )
B[0]++
s = 0
for i = 0 to N - 1
  s = ( s + A[i] ) % K
  B[s]++
ans = 0
for i = 0 to K - 1
  ans = ans + B[i] * ( B[i] - 1 ) / 2
一旦知道它们是S中的x个值为i的单元格,就要计算从值为i的单元格开始到值为i的单元格结束的切片数,这个数字是
x(x-1)/2
。为了解决边缘问题,我们添加一个值为0的单元格

x(x-1)/2
代表什么:假设我们的数组是[4,5,0],4作为前缀和的频率是x,在本例中是3。现在我们可以从x的值得出结论,至少有x-1个数可以被k整除或者mod k等于0。现在,这些x-1数字中可能的子阵列总数为1+2+3…+(x-1)是
((x-1)*((x-1)+1)/2
(从1到N求和的标准公式,其中N代表(x-1)。

公共类子数组可分
{
公共静态void main(字符串[]args)
{
int[]A={4,5,0,-2,-3,1};
SubrayDivisible obj=新的SubrayDivisible();
对象子数组(A,5);
}
私有void getsubarray(int[]A,int K)
{
整数计数=0,s=0;
对于(int i=0;i
private int getsubrayscont(int[]A,int K)
{
int N=A.长度;
int[]B=新的int[K];
for(int i=0;istaticvoidmain(string[]args)
{
int[]A=新的int[]{4,5,0,-2,-3,1};
整数和=0;
int i,j;
整数计数=0;
对于(i=0;i
这里是@Thomash提出的解决方案的Java实现

第二个循环是不必要的,因为我们可以直接增加当前值的答案,然后增加它

为了避免负数组索引,我们还必须调整模块计算

public static int countSubarrays(int[] nums, int k) {
    int[] cache = new int[k];
    cache[0]++;
    int s = 0, counter = 0;
    for (int i = 0; i < nums.length; i++) {
        s = ((s + nums[i]) % k + k) % k;
        counter += cache[s];
        cache[s]++;
    }

    return counter;
}
公共静态int countsubarray(int[]nums,int k){
int[]缓存=新的int[k];
缓存[0]++;
int s=0,计数器=0;
对于(int i=0;i
示例:-

输入数组

int [] nums = {4,3,1,2,1,5,2};
K是3

连续和

4,7,8,10,11,16,18
将上述连续和数组除以3

1,1,2,1,2,1,0
我们有四个1,两个2,一个0

因此,总计数将为(4*3)/2+(2*1)/2+(2*1)/2=8

(4*3)/2来自从四个中选择任意两个1,即nC2=n(n-1)/2

这是节目

4,7,8,10,11,16,18
公共静态长计数子raydivbyk(int k,int[]nums){

Map moduleuscountmap=newhashmap();
int[]concessum=新的int[nums.length];
求和[0]=nums[0];
对于(inti=1;i谢谢,@damluar,但是它非常整洁!我只想添加一些评论

  • 输出应该是7,而不是6。因为我们有7个子数组可以被k整除,如下所示,添加
    res+=storedArray[0];
    来修复它
  • {4,5,0,-2,-3,1};{5};{5,0};{5,0,-2,-3};{0};{0,-2,-3};{-2,-3};{-2,-3}

  • 初始化代码> Cache [0 ]++;取决于语言,如果使用C++,则需要,但对于java [].< 代码:

    公共类HelloWorld{
    公共静态void main(字符串[]args){
    int[]A=新的int[]{4,5,0,-2,-3,1};
    int k=5;
    int ans=0;
    System.out.println(countSubArray(A,k));//输出=7
    }
    公共静态int countSubArray(int[]nums,int k){
    int[]storedArray=新的int[k];
    int sum=0,res=0;
    
    对于(inti=0;iIt不会改变任何东西,我的解决方案仍然有效。B[0]++和B[S]是什么++意味着?@Thomash从理论的角度来看,模仅为正数定义。对于负数,模没有定义的值。如果你声称你的解决方案适用于负数,你应该定义模如何适用于负数。
    B[0]++
    的值是多少?
    ans=ans+B[i]*(B[i]-1)/2
    我想向其他任何不明白的人澄清这一点:B包含nu
    1,1,2,1,2,1,0
    
        Map<Integer, Integer> modulusCountMap = new HashMap<Integer, Integer>();
        int [] consecSum = new int[nums.length];
        consecSum[0]=nums[0];
    
        for(int i=1;i<nums.length;i++){
            consecSum[i]= consecSum[i-1] +nums[i];
        }
    
        for(int i=0;i<nums.length;i++){
            consecSum[i]= consecSum[i]%k;
    
                if(consecSum[i]==0 && modulusCountMap.get(consecSum[i])==null){
                    modulusCountMap.put(consecSum[i], 2);
                }else{
                    modulusCountMap.put(consecSum[i], modulusCountMap.get(consecSum[i])==null ? 1 : modulusCountMap.get(consecSum[i])+1);
                }
    
        }
    
        int count = 0;
    
        for (Integer val : modulusCountMap.values()) {
            count = count +  (val*(val-1))/2;
        }
    
        return count;
    }
    
    static long customOptimizedCountSubArrayDivByK(int k, int[] nums) {
    
            Map<Integer, Integer> modulusCountMap = new HashMap<Integer, Integer>();
            int [] quotient = new int[nums.length];
            quotient[0]=nums[0]%3;
    
    
    
            if(quotient[0]==0){
                modulusCountMap.put(quotient[0], 2);
            }else{
                modulusCountMap.put(quotient[0], 1);
            }
    
    
            for(int i=1;i<nums.length;i++){
                quotient[i]= (quotient[i-1] + nums[i])%3;
    
    
                    if(quotient[i]==0 && modulusCountMap.get(quotient[i])==null){
                        modulusCountMap.put(quotient[i], 2);
                    }else{
                        modulusCountMap.put(quotient[i], modulusCountMap.get(quotient[i])==null ? 1 : modulusCountMap.get(quotient[i])+1);
                    }
    
            }
    
            int count = 0;
    
            for (Integer val : modulusCountMap.values()) {
                count = count +  (val*(val-1))/2;
            }
    
            return count;
        }
    
    public class HelloWorld{
    
    public static void main(String []args){
        int [] A = new int[] {4,5,0,-2,-3,1};
        int k = 5;
        int ans=0;
        System.out.println(countSubArray(A, k)); // output = 7
    
    }
    
    public static int countSubArray(int [] nums, int k){
        int [] storedArray = new int[k];
        int sum=0, res=0;
        for(int i=0; i<nums.length; i++){
            sum = (((sum + nums[i]) % k) + k) % k;
            res += storedArray[sum];
            storedArray[sum]++;
    
        }
        res += storedArray[0];
        return res; 
    }
    }