📜  计算给定数组中大小为k的反转

📅  最后修改于: 2021-04-17 08:36:49             🧑  作者: Mango

给定n个不同整数的数组a_{1}, a_{2}, ..., a_{n}和一个整数k。找出一个这样的子序列数a_{i_{1}} > a_{i_{2}} > ... > a_{i_{k}} , 和1 <= i_{1} < i_{2} < ... < i_{k} <= n 。换句话说,输出长度为k的求反总数。

例子:

Input : a[] = {9, 3, 6, 2, 1}, k = 3        
Output : 7
The seven inversions are {9, 3, 2}, {9, 3, 1}, 
{9, 6, 2}, {9, 6, 1}, {9, 2, 1}, {3, 2, 1} and
{6, 2, 1}.

Input : a[] = {5, 6, 4, 9, 2, 7, 1}, k = 4
Output : 2
The two inversions are {5, 4, 2, 1}, {6, 4, 2, 1}.

我们已经在这里讨论了长度3的倒数计算。这篇文章将使用二进制索引树概括该方法,并使用BIT进行计数反演。可以从Peter M. Fenwick在此处发布的实际论文中找到有关二叉索引树的更多信息。

1.首先,我们首先将给定的数组转换为元素的排列1, 2, 3, ..., n (请注意,这总是可能的,因为元素是不同的)。
2.方法是维护一组k棵Fenwick树。让它表示为bit[k][n]在哪里bit[l][x] ,跟踪l –始于的长度子序列x
3.我们从转换后的数组的末尾开始迭代。对于每个转换后的数组元素x ,我们将Fenwick树集更新为:对于每个1 <= l <= k ,每个子序列的长度l开头的数字小于x也是长度序列的一部分l+1
最终结果是根据出现的总和得出的(k, n)

下面讨论了该实现:

C++
// C++ program to count inversions of size k using
// Binary Indexed Tree
#include 
using namespace std;
  
// It is beneficial to declare the 2D BIT globally 
// since passing it into functions will create 
// additional overhead
const int K = 51;
const int N = 100005;
int BIT[K][N] = { 0 };
  
// update function. "t" denotes the t'th Binary 
// indexed tree
void updateBIT(int t, int i, int val, int n)
{
    // Traversing the t'th BIT
    while (i <= n) {
        BIT[t][i] = BIT[t][i] + val;
        i = i + (i & (-i));
    }
}
  
// function to get the sum.
// "t" denotes the t'th Binary indexed tree
int getSum(int t, int i)
{
    int res = 0;
  
    // Traversing the t'th BIT
    while (i > 0) {
        res = res + BIT[t][i];
        i = i - (i & (-i));
    }
    return res;
}
  
// Converts an array to an array with values from 1 to n
// and relative order of smaller and greater elements 
// remains same.  For example, {7, -90, 100, 1} is
// converted to {3, 1, 4, 2 }
void convert(int arr[], int n)
{
    // Create a copy of arr[] in temp and sort 
    // the temp array in increasing order
    int temp[n];
    for (int i = 0; i < n; i++)
        temp[i] = arr[i];
    sort(temp, temp + n);
  
    // Traverse all array elements
    for (int i = 0; i < n; i++) {
  
        // lower_bound() Returns pointer to the 
        // first element greater than or equal
        // to arr[i]
        arr[i] = lower_bound(temp, temp + n, 
                           arr[i]) - temp + 1;
    }
}
  
// Returns count of inversions of size three
int getInvCount(int arr[], int n, int k)
{
    // Convert arr[] to an array with values from 
    // 1 to n and relative order of smaller and
    // greater elements remains same.  For example, 
    // {7, -90, 100, 1} is converted to {3, 1, 4, 2 }
    convert(arr, n);
  
    // iterating over the converted array in 
    // reverse order.
    for (int i = n - 1; i >= 0; i--) {
        int x = arr[i];
  
        // update the BIT for l = 1
        updateBIT(1, x, 1, n);
  
        // update BIT for all other BITs
        for (int l = 1; l < k; l++) {
            updateBIT(l + 1, x, getSum(l, x - 1), n);
        }
    }
  
    // final result
    return getSum(k, n);
}
  
// Driver program to test above function
int main()
{
    int arr[] = { 5, 6, 4, 9, 3, 7, 2, 1 };
    int n = sizeof(arr) / sizeof(arr[0]);
    int k = 4;
    cout << "Inversion Count : " << getInvCount(arr, n, k);
    return 0;
}


Java
// Java program to count 
// inversions of size k using
// Binary Indexed Tree
import java.io.*;
import java.util.Arrays;
import java.util.ArrayList;
import java.lang.*;
import java.util.Collections;
  
class GFG
{
  
// It is beneficial to declare
// the 2D BIT globally since 
// passing it into functions 
// will create additional overhead
static int K = 51;
static int N = 100005;
static int BIT[][] = new int[K][N];
  
// update function. "t" denotes 
// the t'th Binary indexed tree
static void updateBIT(int t, int i,
                      int val, int n)
{
     
    // Traversing the t'th BIT
    while (i <= n)
    {
        BIT[t][i] = BIT[t][i] + val;
        i = i + (i & (-i));
    }
}
  
// function to get the sum.
// "t" denotes the t'th 
// Binary indexed tree
static int getSum(int t, int i)
{
    int res = 0;
  
    // Traversing the t'th BIT
    while (i > 0) 
    {
        res = res + BIT[t][i];
        i = i - (i & (-i));
    }
    return res;
}
  
// Converts an array to an 
// array with values from
// 1 to n and relative order
// of smaller and greater 
// elements remains same. 
// For example, {7, -90, 100, 1} 
// is converted to {3, 1, 4, 2 }
static void convert(int arr[], int n)
{
    // Create a copy of arr[] in 
    // temp and sort the temp
    // array in increasing order
    int temp[] = new int[n];
    for (int i = 0; i < n; i++)
        temp[i] = arr[i];
    Arrays.sort(temp);
  
    // Traverse all array elements
    for (int i = 0; i < n; i++) 
    {
  
        // lower_bound() Returns 
        // pointer to the first 
        // element greater than 
        // or equal to arr[i]
        arr[i] = Arrays.binarySearch(temp, 
                                     arr[i]) + 1;
    }
}
  
// Returns count of inversions
// of size three
static int getInvCount(int arr[], 
                       int n, int k)
{
      
    // Convert arr[] to an array 
    // with values from 1 to n and 
    // relative order of smaller 
    // and greater elements remains 
    // same. For example, {7, -90, 100, 1}
    // is converted to {3, 1, 4, 2 }
    convert(arr, n);
  
    // iterating over the converted 
    // array in reverse order.
    for (int i = n - 1; i >= 0; i--) 
    {
        int x = arr[i];
  
        // update the BIT for l = 1
        updateBIT(1, x, 1, n);
  
        // update BIT for all other BITs
        for (int l = 1; l < k; l++) 
        {
            updateBIT(l + 1, x, 
                      getSum(l, x - 1), n);
        }
    }
  
    // final result
    return getSum(k, n);
}
  
// Driver Code
public static void main(String[] args)
{
      
    int arr[] = { 5, 6, 4, 9, 
                  3, 7, 2, 1 };
    int n = arr.length;
    int k = 4;
    System.out.println("Inversion Count : " + 
                        getInvCount(arr, n, k));
}
}


Python3
# Python3 program to count inversions 
# of size k using Binary Indexed Tree 
  
# It is beneficial to declare the 2D BIT 
# globally since passing it o functions 
# will create additional overhead 
K = 51
N = 100005
BIT = [[0 for x in range(N)] 
          for y in range(K)] 
  
# update function. "t" denotes
# the t'th Binary indexed tree 
def updateBIT(t, i, val, n): 
  
    # Traversing the t'th BIT 
    while (i <= n): 
        BIT[t][i] = BIT[t][i] + val 
        i = i + (i & (-i)) 
  
# function to get the sum. "t" denotes 
# the t'th Binary indexed tree 
def getSum(t, i):
  
    res = 0
  
    # Traversing the t'th BIT 
    while (i > 0): 
        res = res + BIT[t][i] 
        i = i - (i & (-i)) 
  
    return res 
  
# Converts an array to an array with 
# values from 1 to n and relative order 
# of smaller and greater elements remains
# same. For example, 7, -90, 100, 1 is 
# converted to 3, 1, 4, 2 
def convert( arr, n): 
  
    # Create a copy of arr[] in temp and sort 
    # the temp array in increasing order 
    temp = [0] * n 
    for i in range(n): 
        temp[i] = arr[i] 
    temp = sorted(temp)
    j = 1
    for i in temp:
        arr[arr.index(i)] = j
        j += 1
  
# Returns count of inversions 
# of size three 
def getInvCount(arr, n, k) :
      
    # Convert arr[] to an array with 
    # values from 1 to n and relative 
    # order of smaller and greater elements
    # remains same. For example, 7, -90, 100, 1 
    # is converted to 3, 1, 4, 2 
    convert(arr, n) 
  
    # iterating over the converted array 
    # in reverse order. 
    for i in range(n - 1, -1, -1): 
        x = arr[i] 
  
        # update the BIT for l = 1 
        updateBIT(1, x, 1, n) 
  
        # update BIT for all other BITs 
        for l in range(1, k): 
            updateBIT(l + 1, x, getSum(l, x - 1), n) 
  
    # final result 
    return getSum(k, n) 
  
# Driver code 
if __name__ =="__main__":
    arr = [5, 6, 4, 9, 3, 7, 2, 1] 
    n = 8
    k = 4
    print("Inversion Count :", 
           getInvCount(arr, n, k))
      
# This code is contributed by
# Shubham Singh(SHUBHAMSINGH10)


C#
// C# program to count 
// inversions of size k using 
// Binary Indexed Tree 
using System;
using System.Linq;
  
class GFG 
{ 
  
    // It is beneficial to declare 
    // the 2D BIT globally since 
    // passing it into functions 
    // will create additional overhead 
    static int K = 51; 
    static int N = 100005; 
    static int [,]BIT = new int[K, N]; 
  
    // update function. "t" denotes 
    // the t'th Binary indexed tree 
    static void updateBIT(int t, int i, 
                        int val, int n) 
    { 
  
        // Traversing the t'th BIT 
        while (i <= n) 
        { 
            BIT[t, i] = BIT[t, i] + val; 
            i = i + (i & (-i)); 
        } 
    } 
  
    // function to get the sum. 
    // "t" denotes the t'th 
    // Binary indexed tree 
    static int getSum(int t, int i) 
    { 
        int res = 0; 
  
        // Traversing the t'th BIT 
        while (i > 0) 
        { 
            res = res + BIT[t, i]; 
            i = i - (i & (-i)); 
        } 
        return res; 
    } 
  
    // Converts an array to an 
    // array with values from 
    // 1 to n and relative order 
    // of smaller and greater 
    // elements remains same. 
    // For example, {7, -90, 100, 1} 
    // is converted to {3, 1, 4, 2 } 
    static void convert(int []arr, int n) 
    { 
        // Create a copy of arr[] in 
        // temp and sort the temp 
        // array in increasing order 
        int []temp = new int[n]; 
        for (int i = 0; i < n; i++) 
            temp[i] = arr[i]; 
        Array.Sort(temp); 
  
        // Traverse all array elements 
        for (int i = 0; i < n; i++) 
        { 
  
            // lower_bound() Returns 
            // pointer to the first 
            // element greater than 
            // or equal to arr[i] 
            arr[i] = Array.BinarySearch(temp, 
                                        arr[i]) + 1; 
        } 
    } 
  
    // Returns count of inversions 
    // of size three 
    static int getInvCount(int []arr, 
                        int n, int k) 
    { 
  
        // Convert arr[] to an array 
        // with values from 1 to n and 
        // relative order of smaller 
        // and greater elements remains 
        // same. For example, {7, -90, 100, 1} 
        // is converted to {3, 1, 4, 2 } 
        convert(arr, n); 
  
        // iterating over the converted 
        // array in reverse order. 
        for (int i = n - 1; i >= 0; i--) 
        { 
            int x = arr[i]; 
  
            // update the BIT for l = 1 
            updateBIT(1, x, 1, n); 
  
            // update BIT for all other BITs 
            for (int l = 1; l < k; l++) 
            { 
                updateBIT(l + 1, x, 
                        getSum(l, x - 1), n); 
            } 
        } 
  
        // final result 
        return getSum(k, n); 
    } 
  
    // Driver Code 
    public static void Main(String[] args) 
    { 
  
        int []arr = { 5, 6, 4, 9, 
                    3, 7, 2, 1 }; 
        int n = arr.Length; 
        int k = 4; 
        Console.WriteLine("Inversion Count : " + 
                            getInvCount(arr, n, k)); 
    } 
} 
  
// This code is contributed by PrinciRaj1992


输出:

Inversion Count : 11

时间复杂度\mathcal{O}(nklog(n))
辅助空间\mathcal{O}(nk)

应当指出,这不是解决找到k反转的问题的唯一方法。显然,BIT可以解决的任何问题也可以由Segment Tree解决。此外,我们可以使用基于Merge-Sort的算法,也可以使用基于C++策略的数据结构。同样,以较高的时间复杂度为代价,也可以使用动态编程方法。