Count sub-matrices having sum divisible ‘k’
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++
// 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
// 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. |
Python3
# 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#
// 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 // 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) ?> |
Javascript
<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).
Please Login to comment...