📌  相关文章
📜  计算总和可被 k 整除的所有子数组

📅  最后修改于: 2022-05-13 01:57:47.840000             🧑  作者: Mango

计算总和可被 k 整除的所有子数组

您将获得一个正整数和/或负整数数组以及一个值 K 。任务是找到总和可被 K 整除的所有子数组的计数?
例子 :

Input  : arr[] = {4, 5, 0, -2, -3, 1}, 
         K = 5
Output : 7
// there are 7 sub-arrays whose sum is divisible by K
// {4, 5, 0, -2, -3, 1}
// {5}
// {5, 0}
// {5, 0, -2, -3}
// {0}
// {0, -2, -3}
// {-2, -3}

这个问题的一个简单解决方案是逐一计算所有可能的子数组的总和,并检查是否可以被 K 整除。这种方法的时间复杂度为 O(n^2)。
一个有效的解决方案基于以下观察。

Let there be a subarray (i, j) whose sum is divisible by k
  sum(i, j) = sum(0, j) - sum(0, i-1)
Sum for any subarray can be written as q*k + rem where q 
is a quotient and rem is remainder
Thus,     
    sum(i, j) = (q1 * k + rem1) - (q2 * k + rem2)
    sum(i, j) = (q1 - q2)k + rem1-rem2
     
We see, for sum(i, j) i.e. for sum of any subarray to be
divisible by k, the RHS should also be divisible by k.
(q1 - q2)k is obviously divisible by k, for (rem1-rem2) to 
follow the same, rem1 = rem2 where
    rem1 = Sum of subarray (0, j) % k
    rem2 = Sum of subarray (0, i-1) % k 

因此,如果从索引 i'th 到 j'th 的任何子数组和可以被 k 整除,那么我们可以说a[0]+...a[i-1] (mod k) = a[0]+...+a[ j] (mod k)
上述解释由 Ekta Goel 提供。
所以我们需要找到这样一对满足上述条件的索引 (i, j)。这是算法:

  • 将大小为 k 的辅助数组设为Mod[k] 。这个数组保存我们在将累积总和除以 arr[] 中的任何索引后得到的每个余数的计数。
  • 现在开始计算累积和,同时将其与 K 取模,无论哪个余数,我们得到的余数都增加 1,余数作为 Mod[] 辅助数组中的索引。由每对具有相同值(cumSum % k)的位置组成的子数组构成一个连续范围,其和可被K整除。
  • 现在遍历 Mod[] 辅助数组,对于任何 Mod[i] > 1,我们可以通过(Mod[i]*(Mod[i] – 1))/2种方式为子数组选择任意两对索引。对所有余数 < k 执行相同的操作,并将结果相加,即所有可能的子数组可被 K 整除的数量。

C++
// C++ program to find count of subarrays with
// sum divisible by k.
#include 
using namespace std;
 
// Handles all the cases
// function to find all sub-arrays divisible by k
// modified to handle negative numbers as well
int subCount(int arr[], int n, int k)
{
    // create auxiliary hash array to count frequency
    // of remainders
    int mod[k];
    memset(mod, 0, sizeof(mod));
 
    // Traverse original array and compute cumulative
    // sum take remainder of this current cumulative
    // sum and increase count by 1 for this remainder
    // in mod[] array
    int cumSum = 0;
    for (int i = 0; i < n; i++) {
        cumSum += arr[i];
 
        // as the sum can be negative, taking modulo twice
        mod[((cumSum % k) + k) % k]++;
    }
 
    int result = 0; // Initialize result
 
    // Traverse mod[]
    for (int i = 0; i < k; i++)
 
        // If there are more than one prefix subarrays
        // with a particular mod value.
        if (mod[i] > 1)
            result += (mod[i] * (mod[i] - 1)) / 2;
 
    // add the elements which are divisible by k itself
    // i.e., the elements whose sum = 0
    result += mod[0];
 
    return result;
}
 
// Driver program to run the case
int main()
{
    int arr[] = { 4, 5, 0, -2, -3, 1 };
    int k = 5;
    int n = sizeof(arr) / sizeof(arr[0]);
    cout << subCount(arr, n, k) << endl;
    int arr1[] = { 4, 5, 0, -12, -23, 1 };
    int k1 = 5;
    int n1 = sizeof(arr1) / sizeof(arr1[0]);
    cout << subCount(arr1, n1, k1) << endl;
    return 0;
}
 
// This code is corrected by Ashutosh Kumar


Java
// Java program to find count of
// subarrays with sum divisible by k.
import java.util.*;
 
class GFG {
 
    // Handles all the cases
    // function to find all sub-arrays divisible by k
    // modified to handle negative numbers as well
    static int subCount(int arr[], int n, int k)
    {
 
        // create auxiliary hash array to
        // count frequency of remainders
        int mod[] = new int[k];
        Arrays.fill(mod, 0);
 
        // Traverse original array and compute cumulative
        // sum take remainder of this current cumulative
        // sum and increase count by 1 for this remainder
        // in mod[] array
        int cumSum = 0;
        for (int i = 0; i < n; i++) {
            cumSum += arr[i];
 
            // as the sum can be negative, taking modulo twice
            mod[((cumSum % k) + k) % k]++;
        }
 
        // Initialize result
        int result = 0;
 
        // Traverse mod[]
        for (int i = 0; i < k; i++)
 
            // If there are more than one prefix subarrays
            // with a particular mod value.
            if (mod[i] > 1)
                result += (mod[i] * (mod[i] - 1)) / 2;
 
        // add the elements which are divisible by k itself
        // i.e., the elements whose sum = 0
        result += mod[0];
 
        return result;
    }
 
    // Driver code
    public static void main(String[] args)
    {
 
        int arr[] = { 4, 5, 0, -2, -3, 1 };
        int k = 5;
        int n = arr.length;
        System.out.println(subCount(arr, n, k));
        int arr1[] = { 4, 5, 0, -12, -23, 1 };
        int k1 = 5;
        int n1 = arr1.length;
        System.out.println(subCount(arr1, n1, k1));
    }
}
 
// This code is contributed by Anant Agarwal.


Python3
# Python program to find
# count of subarrays with
# sum divisible by k.
 
# Handles all the cases
# function to find all
# sub-arrays divisible by k
# modified to handle
# negative numbers as well
def subCount(arr, n, k):
 
    # create auxiliary hash
    # array to count frequency
    # of remainders
    mod =[]
    for i in range(k + 1):
        mod.append(0)
   
    # Traverse original array
    # and compute cumulative
    # sum take remainder of this
    # current cumulative
    # sum and increase count by
    # 1 for this remainder
    # in mod[] array
    cumSum = 0
    for i in range(n):
        cumSum = cumSum + arr[i]
          
        # as the sum can be negative,
        # taking modulo twice
        mod[((cumSum % k)+k)% k]= mod[((cumSum % k)+k)% k] + 1
     
   
    result = 0  # Initialize result
      
    # Traverse mod[]
    for i in range(k):
   
        # If there are more than
        # one prefix subarrays
        # with a particular mod value.
        if (mod[i] > 1):
            result = result + (mod[i]*(mod[i]-1))//2
      
    # add the elements which
    # are divisible by k itself
    # i.e., the elements whose sum = 0
    result = result + mod[0]
      
    return result
     
# driver code
 
arr = [4, 5, 0, -2, -3, 1]
k = 5
n = len(arr)
 
print(subCount(arr, n, k))
arr1 = [4, 5, 0, -12, -23, 1]
 
k1 = 5
n1 = len(arr1)
print(subCount(arr1, n1, k1))
 
# This code is contributed
# by Anant Agarwal.


C#
// C# program to find count of
// subarrays with sum divisible by k.
using System;
 
class GFG {
 
    // Handles all the cases
    // function to find all sub-arrays divisible by k
    // modified to handle negative numbers as well
    static int subCount(int[] arr, int n, int k)
    {
        // create auxiliary hash array to
        // count frequency of remainders
        int[] mod = new int[k];
         
        // Traverse original array and compute cumulative
        // sum take remainder of this current cumulative
        // sum and increase count by 1 for this remainder
        // in mod[] array
        int cumSum = 0;
        for (int i = 0; i < n; i++) {
            cumSum += arr[i];
 
            // as the sum can be negative, taking modulo twice
            mod[((cumSum % k) + k) % k]++;
        }
 
        // Initialize result
        int result = 0;
 
        // Traverse mod[]
        for (int i = 0; i < k; i++)
 
            // If there are more than one prefix subarrays
            // with a particular mod value.
            if (mod[i] > 1)
                result += (mod[i] * (mod[i] - 1)) / 2;
 
        // add the elements which are divisible by k itself
        // i.e., the elements whose sum = 0
        result += mod[0];
 
        return result;
    }
 
    // Driver code
    public static void Main()
    {
        int[] arr = { 4, 5, 0, -2, -3, 1 };
        int k = 5;
        int n = arr.Length;
        Console.WriteLine(subCount(arr, n, k));
        int[] arr1 = { 4, 5, 0, -12, -23, 1 };
        int k1 = 5;
        int n1 = arr1.Length;
        Console.WriteLine(subCount(arr1, n1, k1));
    }
}
 
// This code is contributed by vt_m.


Javascript


输出:

7
7