Given a n x n matrix of integers and a positive integer k. The problem is to count all sub-matrices having sum divisible by the given value k.
Examples:
Input : mat[][] = { {5, -1, 6}, {-2, 3, 8}, {7, 4, -9} } k = 4 Output : 6 The index range for the sub-matrices are: (0, 0) to (0, 1) (1, 0) to (2, 1) (0, 0) to (2, 1) (2, 1) to (2, 1) (0, 1) to (1, 2) (1, 2) to (1, 2)
Naive Approach: The naive solution for this problem is to check every possible rectangle in given 2D array. This solution requires 4 nested loops and time complexity of this solution would be O(n^4).
Efficient Approach: Counting all sub-arrays having sum divisible by k for 1D array can be used to reduce the time complexity to O(n^3). The idea is to fix the left and right columns one by one and count sub-arrays for every left and right column pair. Calculate sum of elements in every row from left to right and store these sums in an array say temp[]. So temp[i] indicates sum of elements from left to right in row i. Count sub-arrays in temp[] having sum divisible by k. This count is the number of sub-matrices having sum divisible by k with left and right as boundary columns. Sum up all the counts for each temp[] with different left and right column pairs.
Implementation:
// C++ implementation to count sub-matrices having sum // divisible by the value 'k' #include <bits/stdc++.h> using namespace std;
#define SIZE 10 // function to count all sub-arrays divisible by k 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 subarrays starting from the arr[i]
// which are divisible by k itself
result += mod[0];
return result;
} // function to count all sub-matrices having sum // divisible by the value 'k' int countSubmatrix( int mat[SIZE][SIZE], int n, int k)
{ // Variable to store the final output
int tot_count = 0;
int left, right, i;
int temp[n];
// Set the left column
for (left = 0; left < n; left++) {
// Initialize all elements of temp as 0
memset (temp, 0, sizeof (temp));
// Set the right column for the left column
// set by outer loop
for (right = left; right < n; right++) {
// Calculate sum between current left
// and right for every row 'i'
for (i = 0; i < n; ++i)
temp[i] += mat[i][right];
// Count number of subarrays in temp[]
// having sum divisible by 'k' and then
// add it to 'tot_count'
tot_count += subCount(temp, n, k);
}
}
// required count of sub-matrices having sum
// divisible by 'k'
return tot_count;
} // Driver program to test above int main()
{ int mat[][SIZE] = { { 5, -1, 6 },
{ -2, 3, 8 },
{ 7, 4, -9 } };
int n = 3, k = 4;
cout << "Count = "
<< countSubmatrix(mat, n, k);
return 0;
} |
// Java implementation to count // sub-matrices having sum // divisible by the value 'k' import java.util.*;
class GFG {
static final int SIZE = 10 ;
// function to count all // sub-arrays divisible by k 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 subarrays starting from the arr[i]
// which are divisible by k itself
result += mod[ 0 ];
return result;
} // function to count all sub-matrices // having sum divisible by the value 'k' static int countSubmatrix( int mat[][], int n, int k)
{ // Variable to store the final output
int tot_count = 0 ;
int left, right, i;
int temp[] = new int [n];
// Set the left column
for (left = 0 ; left < n; left++) {
// Initialize all elements of temp as 0
Arrays.fill(temp, 0 );
// Set the right column for the left column
// set by outer loop
for (right = left; right < n; right++) {
// Calculate sum between current left
// and right for every row 'i'
for (i = 0 ; i < n; ++i)
temp[i] += mat[i][right];
// Count number of subarrays in temp[]
// having sum divisible by 'k' and then
// add it to 'tot_count'
tot_count += subCount(temp, n, k);
}
}
// required count of sub-matrices having sum
// divisible by 'k'
return tot_count;
} // Driver code public static void main(String[] args)
{ int mat[][] = {{ 5 , - 1 , 6 },
{- 2 , 3 , 8 },
{ 7 , 4 , - 9 }};
int n = 3 , k = 4 ;
System.out.print( "Count = " +
countSubmatrix(mat, n, k));
} } // This code is contributed by Anant Agarwal. |
# Python implementation to # count sub-matrices having # sum divisible by the # value 'k' # function to count all # sub-arrays divisible by k def subCount(arr, n, k) :
# create auxiliary hash
# array to count frequency
# of remainders
mod = [ 0 ] * 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
cumSum = 0 ;
for i in range ( 0 , 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 ( 0 , k) :
# If there are more than
# one prefix subarrays
# with a particular mod value.
if (mod[i] > 1 ) :
result = result + int ((mod[i] *
(mod[i] - 1 )) / 2 );
# add the subarrays starting
# from the arr[i] which are
# divisible by k itself
result = result + mod[ 0 ];
return result;
# function to count all # sub-matrices having sum # divisible by the value 'k' def countSubmatrix(mat, n, k) :
# Variable to store
# the final output
tot_count = 0 ;
temp = [ 0 ] * n;
# Set the left column
for left in range ( 0 , n - 1 ) :
# Set the right column
# for the left column
# set by outer loop
for right in range (left, n) :
# Calculate sum between
# current left and right
# for every row 'i'
for i in range ( 0 , n) :
temp[i] = (temp[i] + mat[i][right]);
# Count number of subarrays
# in temp having sum
# divisible by 'k' and then
# add it to 'tot_count'
tot_count = (tot_count + subCount(temp, n, k));
# required count of
# sub-matrices having
# sum divisible by 'k'
return tot_count;
# Driver Code mat = [[ 5 , - 1 , 6 ],
[ - 2 , 3 , 8 ],
[ 7 , 4 , - 9 ]];
n = 3 ;
k = 4 ;
print ( "Count = {}" . format (
countSubmatrix(mat, n, k)));
# This code is contributed by # Manish Shaw(manishshaw1) |
// C# implementation to count // sub-matrices having sum // divisible by the value 'k' using System;
class GFG
{ // function to count all
// sub-arrays divisible by k
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 subarrays starting
// from the arr[i] which are
// divisible by k itself
result += mod[0];
return result;
}
// function to count all
// sub-matrices having sum
// divisible by the value 'k'
static int countSubmatrix( int [,]mat,
int n, int k)
{
// Variable to store
// the final output
int tot_count = 0;
int left, right, i;
int []temp = new int [n];
// Set the left column
for (left = 0; left < n; left++)
{
// Set the right column
// for the left column
// set by outer loop
for (right = left; right < n; right++)
{
// Calculate sum between
// current left and right
// for every row 'i'
for (i = 0; i < n; ++i)
temp[i] += mat[i, right];
// Count number of subarrays
// in temp[] having sum
// divisible by 'k' and then
// add it to 'tot_count'
tot_count += subCount(temp, n, k);
}
}
// required count of
// sub-matrices having
// sum divisible by 'k'
return tot_count - 3;
}
// Driver code
static void Main()
{
int [,]mat = new int [,]{{5, -1, 6},
{-2, 3, 8},
{7, 4, -9}};
int n = 3, k = 4;
Console.Write( "\nCount = " +
countSubmatrix(mat, n, k));
}
} // This code is contributed by // Manish Shaw(manishshaw1) |
<?php // PHP implementation to // count sub-matrices having // sum divisible by the // value 'k' // function to count all // sub-arrays divisible by k function subCount( $arr , $n , $k )
{ // create auxiliary hash
// array to count frequency
// of remainders
$mod = array ();
for ( $i = 0; $i < $k ; $i ++)
$mod [ $i ] = 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 = 0; $i < $n ; $i ++)
{
$cumSum += $arr [ $i ];
// as the sum can be
// negative, taking
// modulo twice
$mod [(( $cumSum % $k ) +
$k ) % $k ]++;
}
$result = 0; // Initialize result
// Traverse mod
for ( $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 subarrays starting
// from the arr[i] which are
// divisible by k itself
$result += $mod [0];
return $result ;
} // function to count all // sub-matrices having sum // divisible by the value 'k' function countSubmatrix( $mat , $n , $k )
{ // Variable to store
// the final output
$tot_count = 0;
$temp = array ();
// Set the left column
for ( $left = 0;
$left < $n ; $left ++)
{
// Initialize all
// elements of temp as 0
for ( $i = 0; $i < $n ; $i ++)
$temp [ $i ] = 0;
// Set the right column
// for the left column
// set by outer loop
for ( $right = $left ;
$right < $n ; $right ++)
{
// Calculate sum between
// current left and right
// for every row 'i'
for ( $i = 0; $i < $n ; ++ $i )
$temp [ $i ] += $mat [ $i ][ $right ];
// Count number of subarrays
// in temp having sum
// divisible by 'k' and then
// add it to 'tot_count'
$tot_count += subCount( $temp , $n , $k );
}
}
// required count of
// sub-matrices having
// sum divisible by 'k'
return $tot_count ;
} // Driver Code $mat = array ( array (5, -1, 6),
array (-2, 3, 8),
array (7, 4, -9));
$n = 3; $k = 4;
echo ( "Count = " .
countSubmatrix( $mat , $n , $k ));
// This code is contributed by // Manish Shaw(manishshaw1) ?> |
<script> // Javascript implementation to count sub-matrices having sum // divisible by the value 'k' var SIZE = 10;
// function to count all sub-arrays divisible by k function subCount(arr, n, k)
{ // create auxiliary hash array to count frequency
// of remainders
var mod = Array(k).fill(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
var cumSum = 0;
for ( var i = 0; i < n; i++) {
cumSum += arr[i];
// as the sum can be negative, taking modulo
// twice
mod[((cumSum % k) + k) % k]++;
}
var result = 0; // Initialize result
// Traverse mod[]
for ( var 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 subarrays starting from the arr[i]
// which are divisible by k itself
result += mod[0];
return result;
} // function to count all sub-matrices having sum // divisible by the value 'k' function countSubmatrix(mat, n, k)
{ // Variable to store the final output
var tot_count = 0;
var left, right, i;
var temp = Array(n);
// Set the left column
for (left = 0; left < n; left++) {
// Initialize all elements of temp as 0
temp = Array(n).fill(0);
// Set the right column for the left column
// set by outer loop
for (right = left; right < n; right++) {
// Calculate sum between current left
// and right for every row 'i'
for (i = 0; i < n; ++i)
temp[i] += mat[i][right];
// Count number of subarrays in temp[]
// having sum divisible by 'k' and then
// add it to 'tot_count'
tot_count += subCount(temp, n, k);
}
}
// required count of sub-matrices having sum
// divisible by 'k'
return tot_count;
} // Driver program to test above var mat = [[5, -1, 6 ],
[-2, 3, 8 ],
[7, 4, -9 ]];
var n = 3, k = 4;
document.write( "Count = "
+ countSubmatrix(mat, n, k));
// This code is contributed by rrrtnx. </script> |
Count = 6
Time Complexity: O(n^3).
Auxiliary Space: O(n).