Count inversion pairs in a matrix
Last Updated :
24 Feb, 2023
Given a matrix A of size NxN, we need to find the number of inversion pairs in it. Inversion count in a matrix is defined as the number of pairs satisfying the following conditions :
- x1 ? x2
- y1 ? y2
- A[x2][y2] < A[x1][y1]
Constraints :
- 1 ? Ai,j ? 109
- 1 ? N ? 103
Examples:
For simplicity, let's take a 2x2 matrix :
A = {{7, 5},
{3, 1}};
The inversion pairs are : (7, 5), (3, 1), (7, 3), (5, 1) and (7, 1)
Output : 5
To solve this problem, we need to know the following things :
- Finding number of inversion pairs in a 1D array using Binary Indexed Tree (BIT) https://www.geeksforgeeks.org/count-inversions-array-set-3-using-bit
- 2D BIT https://www.geeksforgeeks.org/two-dimensional-binary-indexed-tree-or-fenwick-tree
Since, we need to find number of inversion pairs in a matrix, first thing we need to do is to store the elements of the matrix in another array, say v and sort the array v so that we can compare the elements of the unsorted matrix with v and find the number of inversion pairs using BIT. But it is given that the values of the elements are very large (109), so we cannot use the values of the elements in the matrix as indices in the BIT. Thus, we need to use the position of the elements as indexes in the 2D BIT.
We are going to use the tuple (-A[i][j], i, j) for each element of the matrix and store it in an array, say ‘v’. Then we need to sort v according to the value of -A[i][j] in ascending order, so that the largest element of the matrix will be stored at index 0 and the smallest one at the last index of v. Now, the problem is reduced to finding inversion pairs in a 1D array, the only exception is that we are going to use a 2D BIT.
Note that here we are using negative values of A[i][j], simply because we are going to traverse v from left to right, i.e., from the largest number in the matrix to the smallest one(because that’s what we do when finding inversion pairs in a 1D array using BIT). One can also use positive values and traverse v from right to left fashion, final result will remain same.
Algorithm :
1. Initialize inv_pair_cnt = 0, which will store the number of inversion pairs.
2. Store the tuple (-A[i][j], i, j) in an array, say v, where A[i][j] is the
element of the matrix A at position (i, j).
3. Sort the array v according to the first element of the tuple, i.e.,
according to the value of -A[i][j].
4. Traverse the array v and do the following :
- Initialize an array, say 'pairs' to store the position (i, j)
of the tuples of v.
- while the current tuple of v and all its adjacent tuples whose
first value, i.e., -A[i][j] is same, do
- Push the current tuple's position pair (i, j) into 'pairs'.
- Add to inv_pair_cnt, the number of elements which are less than
the current element(i.e., A[i][j]) and lie on the right side
in the sorted array v, by calling the query operation of BIT and
passing i and j as arguments.
- For each position pair (i, j) stored in the array 'pairs',
update the position (i, j) in the 2D BIT by 1.
5. Finally, inv_pair_cnt will contain the number of inversion pairs.
Implementation:
C++
#include <bits/stdc++.h>
using namespace std;
#define N 4
void update( int l, int r, int val, int bit[][N + 1])
{
for ( int i = l; i <= N; i += i & -i)
for ( int j = r; j <= N; j += j & -j)
bit[i][j] += val;
}
long long query( int l, int r, int bit[][N + 1])
{
long long ret = 0;
for ( int i = l; i > 0; i -= i & -i)
for ( int j = r; j > 0; j -= j & -j)
ret += bit[i][j];
return ret;
}
long long countInversionPairs( int mat[][N])
{
int bit[N+1][N+1] = {0};
vector<pair< int , pair< int , int > > > v;
for ( int i = 0; i < N; ++i)
for ( int j = 0; j < N; ++j)
v.push_back(make_pair(-mat[i][j],
make_pair(i+1, j+1)));
sort(v.begin(), v.end());
long long inv_pair_cnt = 0;
int i = 0;
while (i < v.size())
{
int curr = i;
vector<pair< int , int > > pairs;
while (curr < v.size() &&
(v[curr].first == v[i].first))
{
pairs.push_back(make_pair(v[curr].second.first,
v[curr].second.second));
inv_pair_cnt += query(v[curr].second.first,
v[curr].second.second, bit);
curr++;
}
vector<pair< int , int > >::iterator it;
for (it = pairs.begin(); it != pairs.end(); ++it)
{
int x = it->first;
int y = it->second;
update(x, y, 1, bit);
}
i = curr;
}
return inv_pair_cnt;
}
int main()
{
int mat[N][N] = { { 4, 7, 2, 9 },
{ 6, 4, 1, 7 },
{ 5, 3, 8, 1 },
{ 3, 2, 5, 6 } };
long long inv_pair_cnt = countInversionPairs(mat);
cout << "The number of inversion pairs are : "
<< inv_pair_cnt << endl;
return 0;
}
|
Python3
N = 4
def update(l, r, val, bit):
i = l
while (i < = N):
j = r
while (j < = N):
bit[i][j] + = val
j + = j & - j
i + = i & - i
def query(l, r, bit):
ret = 0
i = l
while (i > 0 ):
j = r
while (j > 0 ):
ret + = bit[i][j]
j - = j & - j
i - = i & - i
return ret
def countInversionPairs(mat):
bit = [[ 0 for i in range (N + 1 )] for j in range (N + 1 )]
v = []
for i in range (N):
for j in range (N):
v.append([ - mat[i][j], [i + 1 , j + 1 ]])
v.sort()
inv_pair_cnt = 0
i = 0
while (i < len (v)):
curr = i
pairs = []
while (curr < len (v) and (v[curr][ 0 ] = = v[i][ 0 ])):
pairs.append([v[curr][ 1 ][ 0 ], v[curr][ 1 ][ 1 ]])
inv_pair_cnt + = query(v[curr][ 1 ][ 0 ], v[curr][ 1 ][ 1 ], bit)
curr + = 1
for it in pairs:
x = it[ 0 ]
y = it[ 1 ]
update(x, y, 1 , bit)
i = curr
return inv_pair_cnt
mat = [[ 4 , 7 , 2 , 9 ],[ 6 , 4 , 1 , 7 ],
[ 5 , 3 , 8 , 1 ],[ 3 , 2 , 5 , 6 ]]
inv_pair_cnt = countInversionPairs(mat)
print ( "The number of inversion pairs are :" , inv_pair_cnt)
|
C#
using System;
using System.Collections.Generic;
class GFG
{
static int N = 4;
static void update( int l, int r, int val, int [,] bit)
{
for ( int x = l; x <= N; x += (x & -x))
for ( int j = r; j <= N; j += j & -j)
bit[x, j] += val;
}
static int query( int l, int r, int [,] bit)
{
int ret = 0;
for ( int x = l; x > 0; x -= (x & -x))
for ( int j = r; j > 0; j -= (j & -j))
ret += bit[x, j];
return ret;
}
static int countInversionTuples( int [,] mat)
{
int [, ] bit = new int [N + 1, N +1];
for ( int x = 0; x <= N; x++)
for ( int y = 0; y <= N; y++)
bit[x, y] = 0;
List<Tuple< int , Tuple< int , int > > > v = new List<Tuple< int , Tuple< int , int > > >();
for ( int x = 0; x < N; ++x)
for ( int j = 0; j < N; ++j)
v.Add(Tuple.Create(-mat[x, j],
Tuple.Create(x+1, j+1)));
v.Sort();
int inv_Tuple_cnt = 0;
int i = 0;
while (i < v.Count)
{
int curr = i;
List<Tuple< int , int >> Tuples = new List<Tuple< int , int >>();
while (curr < v.Count &&
(v[curr].Item1 == v[i].Item1))
{
Tuples.Add(Tuple.Create(v[curr].Item2.Item1,
v[curr].Item2.Item2));
inv_Tuple_cnt += query(v[curr].Item2.Item1,
v[curr].Item2.Item2, bit);
curr++;
}
foreach ( var it in Tuples)
{
int x = it.Item1;
int y = it.Item2;
update(x, y, 1, bit);
}
i = curr;
}
return inv_Tuple_cnt;
}
public static void Main( string [] args)
{
int [, ] mat = { { 4, 7, 2, 9 },
{ 6, 4, 1, 7 },
{ 5, 3, 8, 1 },
{ 3, 2, 5, 6 } };
int inv_Tuple_cnt = countInversionTuples(mat);
Console.WriteLine( "The number of inversion Tuples are : " + inv_Tuple_cnt);
}
}
|
Javascript
let N = 4
function update(l, r, val, bit)
{
let i = l
while (i <= N)
{
let j = r
while (j <= N)
{
bit[i][j] += val
j += (j & -j)
}
i += (i & -i)
}
return bit
}
function query(l, r, bit)
{
let ret = 0
let i = l
while (i > 0)
{
let j = r
while (j > 0)
{
ret += bit[i][j]
j -= (j & -j)
}
i -= (i & -i)
}
return ret
}
function countInversionPairs(mat)
{
let bit = new Array(N + 1)
for (let i = 0; i <= N; i++)
bit[i] = new Array(N + 1).fill(0)
let v = []
for (let i = 0; i < N; i++)
for ( var j = 0; j < N; j++)
v.push([-mat[i][j], [i + 1, j + 1]])
v.sort( function (a, b) { return a[0] - b[0]})
let inv_pair_cnt = 0
let i = 0
while (i < v.length)
{
let curr = i
let pairs = []
while (curr < v.length && (v[curr][0] == v[i][0]))
{
pairs.push([v[curr][1][0], v[curr][1][1]])
inv_pair_cnt += query(v[curr][1][0], v[curr][1][1], bit)
curr += 1
}
for (let it of pairs)
{
let x = it[0]
let y = it[1]
bit = update(x, y, 1, bit)
}
i = curr
}
return inv_pair_cnt
}
let mat = [[4, 7, 2, 9 ],[ 6, 4, 1, 7 ],
[ 5, 3, 8, 1 ],[3, 2, 5, 6]]
let inv_pair_cnt = countInversionPairs(mat)
console.log( "The number of inversion pairs are " , inv_pair_cnt)
|
Java
import java.util.*;
class Main {
static final int N = 4 ;
static void update( int l, int r, int val, int [][] bit) {
for ( int i = l; i <= N; i += i & -i)
for ( int j = r; j <= N; j += j & -j)
bit[i][j] += val;
}
static long query( int l, int r, int [][] bit) {
long ret = 0 ;
for ( int i = l; i > 0 ; i -= i & -i)
for ( int j = r; j > 0 ; j -= j & -j)
ret += bit[i][j];
return ret;
}
static long countInversionPairs( int [][] mat) {
int [][] bit = new int [N + 1 ][N + 1 ];
List<AbstractMap.SimpleEntry<Integer, AbstractMap.SimpleEntry<Integer, Integer>>> v = new ArrayList<>();
for ( int i = 0 ; i < N; ++i)
for ( int j = 0 ; j < N; ++j)
v.add( new AbstractMap.SimpleEntry<Integer, AbstractMap.SimpleEntry<Integer, Integer>>(-mat[i][j], new AbstractMap.SimpleEntry<Integer, Integer>(i + 1 , j + 1 )));
Collections.sort(v, new Comparator<AbstractMap.SimpleEntry<Integer, AbstractMap.SimpleEntry<Integer, Integer>>>() {
@Override
public int compare(AbstractMap.SimpleEntry<Integer, AbstractMap.SimpleEntry<Integer, Integer>> a, AbstractMap.SimpleEntry<Integer, AbstractMap.SimpleEntry<Integer, Integer>> b) {
return a.getKey().compareTo(b.getKey());
}
});
long invPairCnt = 0 ;
int i = 0 ;
while (i < v.size()) {
int curr = i;
List<AbstractMap.SimpleEntry<Integer, Integer>> pairs = new ArrayList<>();
while (curr < v.size() && (v.get(curr).getKey().equals(v.get(i).getKey()))) {
pairs.add(v.get(curr).getValue());
invPairCnt += query(v.get(curr).getValue().getKey(), v.get(curr).getValue().getValue(), bit);
curr++;
}
for (AbstractMap.SimpleEntry<Integer, Integer> p : pairs) {
int x = p.getKey();
int y = p.getValue();
update(x, y, 1 , bit);
}
i = curr;
}
return invPairCnt;
}
public static void main(String[] args) {
int [][] mat = {{ 4 , 7 , 2 , 9 }, { 6 , 4 , 1 , 7 }, { 5 , 3 , 8 , 1 }, { 3 , 2 , 5 , 6 }};
long invPairCnt = countInversionPairs(mat);
System.out.println( "The number of inversion pairs are: " + invPairCnt);
}
}
|
Output
The number of inversion pairs are : 43
Time Complexity : O(log(NxN)), where N is the size of the matrix
Space Complexity : O(NxN)
Share your thoughts in the comments
Please Login to comment...