计算总和可被 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