📜  计算矩阵中的反转对

📅  最后修改于: 2021-04-17 11:57:13             🧑  作者: Mango

给定大小为NxN的矩阵A ,我们需要找到其中的求反对的数量。矩阵中的反转计数定义为满足以下条件的对数:

限制条件:

  • 1≤A i, j≤10 9
  • 1≤N≤10 3

例子:

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

为了解决这个问题,我们需要了解以下几点:

  1. 使用二进制索引树(BIT)查找一维数组中的反转对数
    https://www.geeksforgeeks.org/count-inversions-array-set-3-using-bit
  2. 2D BIT
    https://www.geeksforgeeks.org/two-Dimension-binary-indexed-tree-or-fenwick-tree

因为我们需要找到一个矩阵中的反转对数,所以我们要做的第一件事是将矩阵中的元素存储在另一个数组中,例如v并对数组v进行排序,以便我们可以比较未排序的矩阵中的元素与v并使用BIT查找反转对的数量。但是假设元素的值非常大(10 9 ),所以我们不能将矩阵中元素的值用作BIT中的索引。因此,我们需要使用元素的位置作为2D BIT中的索引。
我们将对矩阵的每个元素使用元组(-A [i] [j],i,j),并将其存储在数组中,例如’v’。然后,我们需要根据-A [i] [j]的值以升序对v进行排序,以便将矩阵的最大元素存储在索引0处,将最小元素存储在v的最后一个索引处。问题被简化为在1D数组中查找反转对,唯一的例外是我们将使用2D BIT。
请注意,这里我们使用A [i] [j]的负值,只是因为我们要从左到右遍历v,即从矩阵中的最大数到最小的数(因为这是当使用BIT查找一维数组中的反转对)。也可以使用正值并从右向左遍历v,最终结果将保持不变。

算法 :

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.

这是实现:

C++
// C++ program to count the number of inversion
// pairs in a 2D matrix
#include 
using namespace std;
  
// for simplicity, we are taking N as 4
#define N 4
  
// Function to update a 2D BIT. It updates the
// value of bit[l][r] by adding val to bit[l][r]
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;
}
  
// function to find cumulative sum upto
// index (l, r) in the 2D BIT
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;
}
  
// function to count and return the number
// of inversion pairs in the matrix
long long countInversionPairs(int mat[][N])
{
    // the 2D bit array and initialize it with 0.
    int bit[N+1][N+1] = {0};
  
    // v will store the tuple (-mat[i][j], i, j)
    vector > > v;
  
    // store the tuples in the vector v
    for (int i = 0; i < N; ++i)
        for (int j = 0; j < N; ++j)
  
            // Note that we are not using the pair
            // (0, 0) because BIT update and query
            // operations are not done on index 0
            v.push_back(make_pair(-mat[i][j],
                        make_pair(i+1, j+1)));
  
    // sort the vector v according to the
    // first element of the tuple, i.e., -mat[i][j]
    sort(v.begin(), v.end());
  
    // inv_pair_cnt will store the number of
    // inversion pairs
    long long inv_pair_cnt = 0;
  
    // traverse all the tuples of vector v
    int i = 0;
    while (i < v.size())
    {
        int curr = i;
  
        // 'pairs' will store the position of each element,
        // i.e., the pair (i, j) of each tuple of the vector v
        vector > pairs;
  
        // consider the current tuple in v and all its
        // adjacent tuples whose first value, i.e., the
        // value of –mat[i][j] is same
        while (curr < v.size() &&
               (v[curr].first == v[i].first))
        {
            // push the position of the current element in 'pairs'
            pairs.push_back(make_pair(v[curr].second.first,
                                      v[curr].second.second));
  
            // add the number of elements which are
            // less than the current element and lie on the right
            // side in the vector v
            inv_pair_cnt += query(v[curr].second.first,
                                  v[curr].second.second, bit);
  
            curr++;
        }
  
        vector >::iterator it;
  
        // traverse the 'pairs' vector
        for (it = pairs.begin(); it != pairs.end(); ++it)
        {
            int x = it->first;
            int y = it->second;
  
            // update the position (x, y) by 1
            update(x, y, 1, bit);
        }
  
        i = curr;
    }
  
    return inv_pair_cnt;
}
  
// Driver program
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
# Python3 program to count the number of inversion
# pairs in a 2D matrix
  
# for simplicity, we are taking N as 4
N = 4
  
# Function to update a 2D BIT. It updates the
# value of bit[l][r] by adding val to bit[l][r]
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
  
# function to find cumulative sum upto
# index (l, r) in the 2D BIT
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
  
# function to count and return the number
# of inversion pairs in the matrix
def countInversionPairs(mat):
      
    # the 2D bit array and initialize it with 0.
    bit = [[0 for i in range(N + 1)] for j in range(N + 1)]
      
    # v will store the tuple (-mat[i][j], i, j)
    v = []
      
    # store the tuples in the vector v
    for i in range(N):
        for j in range(N):
              
            # Note that we are not using the pair
            # (0, 0) because BIT update and query
            # operations are not done on index 0
            v.append([-mat[i][j], [i + 1, j + 1]])
      
    # sort the vector v according to the
    # first element of the tuple, i.e., -mat[i][j]
    v.sort()
      
    # inv_pair_cnt will store the number of
    # inversion pairs
    inv_pair_cnt = 0
      
    # traverse all the tuples of vector v
    i = 0
    while (i < len(v)):
          
        curr = i
          
        # 'pairs' will store the position of each element,
        # i.e., the pair (i, j) of each tuple of the vector v
        pairs = []
          
        # consider the current tuple in v and all its
        # adjacent tuples whose first value, i.e., the
        # value of –mat[i][j] is same
        while (curr < len(v) and (v[curr][0] == v[i][0])):
              
            # push the position of the current element in 'pairs'
            pairs.append([v[curr][1][0], v[curr][1][1]])
              
            # add the number of elements which are
            # less than the current element and lie on the right
            # side in the vector v
            inv_pair_cnt += query(v[curr][1][0], v[curr][1][1], bit)
            curr += 1
              
        # traverse the 'pairs' vector
        for it in pairs:
            x = it[0]
            y = it[1]
              
            # update the position (x, y) by 1
            update(x, y, 1, bit)
              
        i = curr
      
    return inv_pair_cnt
  
# Driver code
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)
  
# This code is contributed by shubhamsingh10


输出:

The number of inversion pairs are : 43

时间复杂度:O(log(NxN)),其中N是矩阵的大小
空间复杂度:O(NxN)