XOR of a submatrix queries
Last Updated :
27 Aug, 2022
Given an N * N matrix and q queries, each containing position of top-left and bottom-right corner of a rectangular sub-matrix, the task is to find the xor of all the elements from this sub-matrix.
Examples:
Input: arr[][] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}, q[] = {{1, 1, 2, 2}, {1, 2, 2, 2}}
Output:
2
15
Query 1: 5 ^ 6 ^ 8 ^ 9 = 2
Query 2: 6 ^ 9 = 15
Input: arr[][] = {{21, 2}, { 14, 5}}, q[] = {{0, 1, 1, 1}, {0, 0, 1, 1}}
Output:
7
28
A simple solution is to find the XOR of the entire sub-matrix for each query. Thus, the worst case time complexity for each query will be O(n2).
Efficient Approach: We are all familiar with the idea of prefix XOR on linear array i.e.
if arr[] = {1, 2, 3, 4} and we calculate prefixXOR[] = {1, 3, 0, 4} where prefixXOR[i] stores the XOR of values from arr[0] to arr[i]
Then the XOR of sub-array arr[i] to arr[j] can be found as prefixXOR[j] ^ prefixXOR[i – 1]
For example, the XOR of sub-array {2, 3} will be XOR(0, 1) = 1
This is because in the prefixXOR values for {1, 2, 3} and {1}, the value 1 got repeated twice which will give 0 as the XOR result and will not affect the value of the other XOR operations.
We will try to extend the same to the 2-D matrix. We will compute a prefix-XOR matrix which will help us in solving each query in O(1).
In this case, our prefix-XOR matrix at position (R, C) will store the XOR of the rectangular sub-matrix with top-left corner at(0, 0) and bottom-right corner at (R, C).
We calculate the prefix-XOR in two steps.
- Calculate the prefix-XOR for each row of the original matrix from left to right.
- On the above matrix, calculate the prefix XOR for each column from top to bottom.
Once, we have the required prefix XOR-matrix, we can answer the queries with simplicity. XOR of a sub-matrix from (R1, C1) to (R2, C2) can be computed as prefix_xor[R2][C2] ^ prefix_xor[R1 – 1][C2] ^ prefix_xor[R2][C1 – 1] ^ prefix_xor[R1 – 1][C1 – 1].
Note: If R1 or C1 equals 0, then R1 – 1 or C1 – 1 should also be 0.
Below is the implementation of the above approach:
C++
#include <iostream>
#define n 3
using namespace std;
void preComputeXor( int arr[][n], int prefix_xor[][n])
{
for ( int i = 0; i < n; i++)
for ( int j = 0; j < n; j++) {
if (j == 0)
prefix_xor[i][j] = arr[i][j];
else
prefix_xor[i][j]
= (prefix_xor[i][j - 1] ^ arr[i][j]);
}
for ( int i = 0; i < n; i++)
for ( int j = 1; j < n; j++)
prefix_xor[j][i]
= (prefix_xor[j - 1][i] ^ prefix_xor[j][i]);
}
int ansQuerie( int prefix_xor[][n], int x1, int y1, int x2, int y2)
{
int xor_1 = 0, xor_2 = 0, xor_3 = 0;
if (x1 != 0)
xor_1 = prefix_xor[x1 - 1][y2];
if (y1 != 0)
xor_2 = prefix_xor[x2][y1 - 1];
if (x1 != 0 and y1 != 0)
xor_3 = prefix_xor[x1 - 1][y1 - 1];
return ((prefix_xor[x2][y2] ^ xor_1) ^ (xor_2 ^ xor_3));
}
int main()
{
int arr[][n] = { { 1, 2, 3 },
{ 4, 5, 6 },
{ 7, 8, 9 } };
int prefix_xor[n][n];
preComputeXor(arr, prefix_xor);
cout << ansQuerie(prefix_xor, 1, 1, 2, 2) << endl;
cout << ansQuerie(prefix_xor, 1, 2, 2, 2) << endl;
return 0;
}
|
Java
class GfG
{
static int n = 3 ;
static void preComputeXor( int arr[][],
int prefix_xor[][])
{
for ( int i = 0 ; i < n; i++)
for ( int j = 0 ; j < n; j++)
{
if (j == 0 )
prefix_xor[i][j] = arr[i][j];
else
prefix_xor[i][j] =
(prefix_xor[i][j - 1 ] ^ arr[i][j]);
}
for ( int i = 0 ; i < n; i++)
for ( int j = 1 ; j < n; j++)
prefix_xor[j][i] =
(prefix_xor[j - 1 ][i] ^ prefix_xor[j][i]);
}
static int ansQuerie( int prefix_xor[][], int x1,
int y1, int x2, int y2)
{
int xor_1 = 0 , xor_2 = 0 , xor_3 = 0 ;
if (x1 != 0 )
xor_1 = prefix_xor[x1 - 1 ][y2];
if (y1 != 0 )
xor_2 = prefix_xor[x2][y1 - 1 ];
if (x1 != 0 && y1 != 0 )
xor_3 = prefix_xor[x1 - 1 ][y1 - 1 ];
return ((prefix_xor[x2][y2] ^ xor_1) ^ (xor_2 ^ xor_3));
}
public static void main(String[] args)
{
int arr[][] = new int [][]{{ 1 , 2 , 3 },
{ 4 , 5 , 6 },
{ 7 , 8 , 9 }};
int prefix_xor[][] = new int [n][n];
preComputeXor(arr, prefix_xor);
System.out.println(ansQuerie(prefix_xor, 1 , 1 , 2 , 2 ));
System.out.println(ansQuerie(prefix_xor, 1 , 2 , 2 , 2 ));
}
}
|
Python3
n = 3
def preComputeXor(arr, prefix_xor):
for i in range (n):
for j in range (n):
if (j = = 0 ):
prefix_xor[i][j] = arr[i][j]
else :
prefix_xor[i][j] = (prefix_xor[i][j - 1 ] ^
arr[i][j])
for i in range (n):
for j in range ( 1 , n):
prefix_xor[j][i] = (prefix_xor[j - 1 ][i] ^
prefix_xor[j][i])
def ansQuerie(prefix_xor, x1, y1, x2, y2):
xor_1, xor_2, xor_3 = 0 , 0 , 0
if (x1 ! = 0 ):
xor_1 = prefix_xor[x1 - 1 ][y2]
if (y1 ! = 0 ):
xor_2 = prefix_xor[x2][y1 - 1 ]
if (x1 ! = 0 and y1 ! = 0 ):
xor_3 = prefix_xor[x1 - 1 ][y1 - 1 ]
return ((prefix_xor[x2][y2] ^ xor_1) ^
(xor_2 ^ xor_3))
arr = [[ 1 , 2 , 3 ],
[ 4 , 5 , 6 ],
[ 7 , 8 , 9 ]]
prefix_xor = [[ 0 for i in range (n)]
for i in range (n)]
preComputeXor(arr, prefix_xor)
print (ansQuerie(prefix_xor, 1 , 1 , 2 , 2 ))
print (ansQuerie(prefix_xor, 1 , 2 , 2 , 2 ))
|
C#
using System;
class GfG
{
static int n = 3;
static void preComputeXor( int [,]arr,
int [,]prefix_xor)
{
for ( int i = 0; i < n; i++)
for ( int j = 0; j < n; j++)
{
if (j == 0)
prefix_xor[i, j] = arr[i, j];
else
prefix_xor[i, j] =
(prefix_xor[i, j - 1] ^ arr[i, j]);
}
for ( int i = 0; i < n; i++)
for ( int j = 1; j < n; j++)
prefix_xor[j, i] =
(prefix_xor[j - 1, i] ^
prefix_xor[j, i]);
}
static int ansQuerie( int [,]prefix_xor, int x1,
int y1, int x2, int y2)
{
int xor_1 = 0, xor_2 = 0, xor_3 = 0;
if (x1 != 0)
xor_1 = prefix_xor[x1 - 1, y2];
if (y1 != 0)
xor_2 = prefix_xor[x2, y1 - 1];
if (x1 != 0 && y1 != 0)
xor_3 = prefix_xor[x1 - 1, y1 - 1];
return ((prefix_xor[x2,y2] ^ xor_1) ^
(xor_2 ^ xor_3));
}
public static void Main()
{
int [,]arr = {{ 1, 2, 3 },
{ 4, 5, 6 },
{ 7, 8, 9 }};
int [,]prefix_xor = new int [n, n];
preComputeXor(arr, prefix_xor);
Console.WriteLine(ansQuerie(prefix_xor, 1, 1, 2, 2));
Console.WriteLine(ansQuerie(prefix_xor, 1, 2, 2, 2));
}
}
|
PHP
<?php
$n = 3;
function preComputeXor( $arr , & $prefix_xor )
{
global $n ;
for ( $i = 0; $i < $n ; $i ++)
for ( $j = 0; $j < $n ; $j ++)
{
if ( $j == 0)
$prefix_xor [ $i ][ $j ] = $arr [ $i ][ $j ];
else
$prefix_xor [ $i ][ $j ] = ( $prefix_xor [ $i ][ $j - 1] ^
$arr [ $i ][ $j ]);
}
for ( $i = 0; $i < $n ; $i ++)
for ( $j = 1; $j < $n ; $j ++)
$prefix_xor [ $j ][ $i ] = ( $prefix_xor [ $j - 1][ $i ] ^
$prefix_xor [ $j ][ $i ]);
}
function ansQuerie( $prefix_xor , $x1 ,
$y1 , $x2 , $y2 )
{
$xor_1 = $xor_2 = $xor_3 = 0;
if ( $x1 != 0)
$xor_1 = $prefix_xor [ $x1 - 1][ $y2 ];
if ( $y1 != 0)
$xor_2 = $prefix_xor [ $x2 ][ $y1 - 1];
if ( $x1 != 0 and $y1 != 0)
$xor_3 = $prefix_xor [ $x1 - 1][ $y1 - 1];
return (( $prefix_xor [ $x2 ][ $y2 ] ^ $xor_1 ) ^
( $xor_2 ^ $xor_3 ));
}
$arr = array ( array ( 1, 2, 3 ),
array ( 4, 5, 6 ),
array ( 7, 8, 9 ));
$prefix_xor = array_fill (0, $n ,
array_fill (0, $n , 0));
preComputeXor( $arr , $prefix_xor );
echo ansQuerie( $prefix_xor , 1, 1, 2, 2) . "\n" ;
echo ansQuerie( $prefix_xor , 1, 2, 2, 2);
?>
|
Javascript
<script>
var n = 3;
function preComputeXor(arr , prefix_xor)
{
for (i = 0; i < n; i++)
for (j = 0; j < n; j++) {
if (j == 0)
prefix_xor[i][j] = arr[i][j];
else
prefix_xor[i][j] =
(prefix_xor[i][j - 1] ^ arr[i][j]);
}
for (i = 0; i < n; i++)
for (j = 1; j < n; j++)
prefix_xor[j][i] =
(prefix_xor[j - 1][i] ^ prefix_xor[j][i]);
}
function ansQuerie(prefix_xor , x1 , y1 , x2 , y2) {
var xor_1 = 0, xor_2 = 0, xor_3 = 0;
if (x1 != 0)
xor_1 = prefix_xor[x1 - 1][y2];
if (y1 != 0)
xor_2 = prefix_xor[x2][y1 - 1];
if (x1 != 0 && y1 != 0)
xor_3 = prefix_xor[x1 - 1][y1 - 1];
return ((prefix_xor[x2][y2] ^ xor_1) ^
(xor_2 ^ xor_3));
}
var arr = [[ 1, 2, 3 ], [ 4, 5, 6 ],
[ 7, 8, 9 ] ];
var prefix_xor = Array(n);
for ( var i = 0;i<n;i++)
prefix_xor[i] = Array(n).fill(0);
preComputeXor(arr, prefix_xor);
document.write(ansQuerie(prefix_xor, 1, 1, 2, 2)+
"<br/>" );
document.write(ansQuerie(prefix_xor, 1, 2, 2, 2));
</script>
|
Time Complexity: O(n2)
Auxiliary Space: O(n2), since n2 extra space has been taken.
Like Article
Suggest improvement
Share your thoughts in the comments
Please Login to comment...