计算子数组中的反转
给定一个数组arr[] ,目标是计算所有子数组中的反转次数。反转是一对索引i和j使得i > j和arr[i] < arr[j] 。从索引x到y ( x<= y)的子数组由元素的arr[x], arr[x+1], ..., arr[y]组成。数组arr[]也可以包含重复的元素。
例子:
Input: arr[] = {3, 6, 1, 6, 5, 3, 9}
Output:
0 0 2 2 4 7 7
0 0 1 1 3 6 6
0 0 0 0 1 3 3
0 0 0 0 1 3 3
0 0 0 0 0 1 1
0 0 0 0 0 0 0
0 0 0 0 0 0 0
Explanation:
The element in the i’th row and j’th column of the output denotes the number of inversions from index i to j (inclusive). Consider i = 1 and j = 4 (assuming 0-based indexing), the number of inversions in the subarray {6, 1, 6, 5} is 3. The element pairs are (6, 1), (6, 5) and (6, 5) (from the second 6).
Input: arr[] = {3, 2, 1}
Output:
0 1 3
0 0 1
0 0 0
Explanation:
From index 0 to 1 there is 1 inversion, from index 2 to 3 there is 1 inversion and from index 0 to 2 there are 3 inversions. The i’th row and j’th column of the output is 0 if i >= j.
朴素方法:一种朴素的方法是生成所有可能的子数组并计算每个子数组中的反转次数。
下面是上述方法的实现:
C++
// C++ program for the above approach
#include
using namespace std;
// Function to count the number of
// inversions in all the sub-arrays
void findSubarrayInversions(int arr[], int n)
{
int inversions[n][n];
// Initializing the inversion count
// of each subarray to 0
// inversions[i][j] will denote
// the number of inversions
// from index i to index j inclusive
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
inversions[i][j] = 0;
}
}
// Generating all subarray
for (int i = 0; i < n; i++) {
for (int j = i; j < n; j++) {
int ans = 0;
// counting the number of inversions
// for a subarray
for (int x = i; x <= j; x++) {
for (int y = x; y <= j; y++) {
if (arr[x] > arr[y])
ans++;
}
}
inversions[i][j] = ans;
}
}
// Printing the number of inversions
// of all subarrays
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
cout << inversions[i][j] << " ";
}
cout << "\n";
}
}
// Driver Code
int main()
{
// Given Input
int n = 7;
int arr[n] = { 3, 6, 1, 6, 5, 3, 9 };
// Function Call
findSubarrayInversions(arr, n);
}
Java
// Java program for the above approach
class GFG{
// Function to count the number of
// inversions in all the sub-arrays
static void findSubarrayInversions(int arr[], int n)
{
int [][]inversions = new int[n][n];
// Initializing the inversion count
// of each subarray to 0
// inversions[i][j] will denote
// the number of inversions
// from index i to index j inclusive
for(int i = 0; i < n; i++)
{
for(int j = 0; j < n; j++)
{
inversions[i][j] = 0;
}
}
// Generating all subarray
for(int i = 0; i < n; i++)
{
for(int j = i; j < n; j++)
{
int ans = 0;
// Counting the number of inversions
// for a subarray
for(int x = i; x <= j; x++)
{
for(int y = x; y <= j; y++)
{
if (arr[x] > arr[y])
ans++;
}
}
inversions[i][j] = ans;
}
}
// Printing the number of inversions
// of all subarrays
for(int i = 0; i < n; i++)
{
for(int j = 0; j < n; j++)
{
System.out.print(inversions[i][j] + " ");
}
System.out.println();
}
}
// Driver Code
public static void main(String args[])
{
// Given Input
int n = 7;
int []arr = { 3, 6, 1, 6, 5, 3, 9 };
// Function Call
findSubarrayInversions(arr, n);
}
}
// This code is contributed by SoumikMondal.
Python3
# Python3 program for the above approach
# Function to count the number of
# inversions in all the sub-arrays
def findSubarrayInversions(arr, n):
inversions = [[0 for i in range(n)]
for j in range(n)]
# Initializing the inversion count
# of each subarray to 0
# inversions[i][j] will denote
# the number of inversions
# from index i to index j inclusive
# Generating all subarray
for i in range(0, n):
for j in range(0, n):
ans = 0
# Counting the number of inversions
# for a subarray
for x in range(i, j + 1):
for y in range(x, j + 1):
if (arr[x] > arr[y]):
ans += 1
# Print(ans)
inversions[i][j] = ans
# Printing the number of inversions
# of all subarrays
for i in range(0, n):
for j in range(0, n):
print(inversions[i][j], end = " ")
print()
# Driver Code
# Given Input
n = 7
arr = [ 3, 6, 1, 6, 5, 3, 9 ]
# Function Call
findSubarrayInversions(arr, n)
# This code is contributed by amreshkumar3
C#
// C# program for the above approach
using System;
using System.Collections.Generic;
class GFG{
// Function to count the number of
// inversions in all the sub-arrays
static void findSubarrayInversions(int []arr, int n)
{
int [,]inversions = new int[n,n];
// Initializing the inversion count
// of each subarray to 0
// inversions[i][j] will denote
// the number of inversions
// from index i to index j inclusive
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
inversions[i,j] = 0;
}
}
// Generating all subarray
for (int i = 0; i < n; i++)
{
for (int j = i; j < n; j++)
{
int ans = 0;
// counting the number of inversions
// for a subarray
for (int x = i; x <= j; x++) {
for (int y = x; y <= j; y++) {
if (arr[x] > arr[y])
ans++;
}
}
inversions[i,j] = ans;
}
}
// Printing the number of inversions
// of all subarrays
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
Console.Write(inversions[i,j] + " ");
}
Console.WriteLine();
}
}
// Driver Code
public static void Main()
{
// Given Input
int n = 7;
int []arr = { 3, 6, 1, 6, 5, 3, 9 };
// Function Call
findSubarrayInversions(arr, n);
}
}
// This code is contributed by ipg2016107.
Javascript
C++
// C++ program for the above approach
#include
using namespace std;
// Function to count the number of
// inversions in all the sub-arrays
void findSubarrayInversions(int arr[], int n)
{
int greater[n][n];
int prefix[n][n];
int inversions[n][n];
// Initializing the arrays to 0
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
greater[i][j] = 0;
prefix[i][j] = 0;
inversions[i][j] = 0;
}
}
// For each pair of indices i and j
// calculating the number of elements
// from i to j inclusive which are
// greater than arr[i]
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
greater[i][j] = greater[i][j - 1];
if (arr[i] > arr[j])
greater[i][j]++;
}
}
// Building the prefix table.
// Prefix[i][j] denotes the sum of
// greater[0][j], greater[1][j] ... greater[i][j]
for (int j = 0; j < n; j++) {
prefix[0][j] = greater[0][j];
for (int i = 1; i < n; i++) {
prefix[i][j] = prefix[i - 1][j] + greater[i][j];
}
}
// Calculating the inversion count for
// each subarray using the prefix table
for (int i = 0; i < n; i++) {
for (int j = i; j < n; j++) {
if (i == 0)
inversions[i][j] = prefix[j][j];
else
inversions[i][j] = prefix[j][j]
- prefix[i - 1][j];
}
}
// Printing the values of the number
// of inversions in each subarray
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
cout << inversions[i][j] << " ";
}
cout << "\n";
}
}
// Driver Code
int main()
{
// Given Input
int n = 7;
int arr[n] = { 3, 6, 1, 6, 5, 3, 9 };
// Function Call
findSubarrayInversions(arr, n);
}
Python3
# Python3 program for the above approach
# Function to count the number of
# inversions in all the sub-arrays
def findSubarrayInversions(arr, n):
# Initializing the arrays to 0
greater = [[0 for i in range(n)]
for j in range(n)]
prefix = [[0 for i in range(n)]
for j in range(n)]
inversions = [[0 for i in range(n)]
for j in range(n)]
# For each pair of indices i and j
# calculating the number of elements
# from i to j inclusive which are
# greater than arr[i]
for i in range(0, n):
for j in range(i + 1, n):
greater[i][j] = greater[i][j - 1]
if (arr[i] > arr[j]):
greater[i][j] += 1
# Building the prefix table.
# Prefix[i][j] denotes the sum of
# greater[0][j], greater[1][j] ... greater[i][j]
for j in range(0, n):
prefix[0][j] = greater[0][j]
for i in range(1, n):
prefix[i][j] = (prefix[i - 1][j] +
greater[i][j])
# Calculating the inversion count for
# each subarray using the prefix table
for i in range(0, n):
for j in range(i, n):
if (i == 0):
inversions[i][j] = prefix[j][j]
else:
inversions[i][j] = (prefix[j][j] -
prefix[i - 1][j])
# Printing the values of the number
# of inversions in each subarray
for i in range(0, n):
for j in range(0, n):
print(inversions[i][j], end = " ")
print()
# Driver Code
# Given Input
n = 7
arr = [ 3, 6, 1, 6, 5, 3, 9 ]
# Function Call
findSubarrayInversions(arr, n)
# This code is contributed by amreshkumar3
Javascript
0 0 2 2 4 7 7
0 0 1 1 3 6 6
0 0 0 0 1 3 3
0 0 0 0 1 3 3
0 0 0 0 0 1 1
0 0 0 0 0 0 0
0 0 0 0 0 0 0
时间复杂度: O(N 4 )
辅助空间: O(N 2 )
高效方法:上述方法可以使用此处给出的方法进行一些优化,以查找子数组中的反转次数。首先看一些观察来解决这个问题:
First create a 2d array greater[][], where greater[i][j] denotes the number of elements in the range i to j which are greater than arr[i]. Iterate over the array and for each element, find the number of elements to its right which are less than the element. This can be done using a naive approach in O(N^2). Now to find the number of inversions in a range say x to y, the answer will be greater[x][y] + greater[x+1][y] + … + greater[y-1][y] + greater[y][y].
With the greater[][] table this value can be calculated in O(n) for each sub-array resulting in a complexity of O(n^3).(There are O(n^2) sub-array, and it takes O(n) time to compute the number of inversions in each sub-array). To find this value in O(1) each time build a prefix sum table from the greater[][] table where prefix[i][j] denotes the value of greater[0][j] + greater[1][j] + … + greater[i][j]. This table can also be built in O(N^2) time. Now the answer for each sub-array from x to y (inclusive) would become prefix[y][y] – prefix[x-1][y] if x >= 1 and prefix[y][y] if x = 0.
请按照以下步骤解决此问题:
- 初始化数组greater[][]来存储 其中Greater[i][j]表示i到j范围内大于arr[i] 的元素个数,prefix[][]存储子数组的前缀和, inversions[][]存储反转次数。
- 使用变量i在[0, N-1]范围内迭代:
- 使用变量j在[i+1, N-1]范围内迭代:
- 将更大[i][j]更新为更大[i][j-1]
- 如果arr[i]大于arr[j],则将greater[i][j]增加1。
- 使用变量j在[i+1, N-1]范围内迭代:
- 使用变量i在[0, N-1]范围内迭代:
- 将前缀 [0][j]更新为更大 [0][j]
- 使用变量j在范围[1, N-1]中迭代,并将prefix[i][j]更新为prefix[i-1][j] + greater[i][j]。
- 使用变量i在[0, N-1]范围内迭代:
- 使用变量j在范围[i, N-1]中迭代:
- 如果i = 0,则将inversions[i][j]更新为prefix[j][j]
- 否则,将inversions[i][j]更新为prefix[j][j] + prefix[i-1][j]。
- 使用变量j在范围[i, N-1]中迭代:
- 完成上述步骤后,打印inversions[][]数组作为答案。
下面是上述方法的实现:
C++
// C++ program for the above approach
#include
using namespace std;
// Function to count the number of
// inversions in all the sub-arrays
void findSubarrayInversions(int arr[], int n)
{
int greater[n][n];
int prefix[n][n];
int inversions[n][n];
// Initializing the arrays to 0
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
greater[i][j] = 0;
prefix[i][j] = 0;
inversions[i][j] = 0;
}
}
// For each pair of indices i and j
// calculating the number of elements
// from i to j inclusive which are
// greater than arr[i]
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
greater[i][j] = greater[i][j - 1];
if (arr[i] > arr[j])
greater[i][j]++;
}
}
// Building the prefix table.
// Prefix[i][j] denotes the sum of
// greater[0][j], greater[1][j] ... greater[i][j]
for (int j = 0; j < n; j++) {
prefix[0][j] = greater[0][j];
for (int i = 1; i < n; i++) {
prefix[i][j] = prefix[i - 1][j] + greater[i][j];
}
}
// Calculating the inversion count for
// each subarray using the prefix table
for (int i = 0; i < n; i++) {
for (int j = i; j < n; j++) {
if (i == 0)
inversions[i][j] = prefix[j][j];
else
inversions[i][j] = prefix[j][j]
- prefix[i - 1][j];
}
}
// Printing the values of the number
// of inversions in each subarray
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
cout << inversions[i][j] << " ";
}
cout << "\n";
}
}
// Driver Code
int main()
{
// Given Input
int n = 7;
int arr[n] = { 3, 6, 1, 6, 5, 3, 9 };
// Function Call
findSubarrayInversions(arr, n);
}
Python3
# Python3 program for the above approach
# Function to count the number of
# inversions in all the sub-arrays
def findSubarrayInversions(arr, n):
# Initializing the arrays to 0
greater = [[0 for i in range(n)]
for j in range(n)]
prefix = [[0 for i in range(n)]
for j in range(n)]
inversions = [[0 for i in range(n)]
for j in range(n)]
# For each pair of indices i and j
# calculating the number of elements
# from i to j inclusive which are
# greater than arr[i]
for i in range(0, n):
for j in range(i + 1, n):
greater[i][j] = greater[i][j - 1]
if (arr[i] > arr[j]):
greater[i][j] += 1
# Building the prefix table.
# Prefix[i][j] denotes the sum of
# greater[0][j], greater[1][j] ... greater[i][j]
for j in range(0, n):
prefix[0][j] = greater[0][j]
for i in range(1, n):
prefix[i][j] = (prefix[i - 1][j] +
greater[i][j])
# Calculating the inversion count for
# each subarray using the prefix table
for i in range(0, n):
for j in range(i, n):
if (i == 0):
inversions[i][j] = prefix[j][j]
else:
inversions[i][j] = (prefix[j][j] -
prefix[i - 1][j])
# Printing the values of the number
# of inversions in each subarray
for i in range(0, n):
for j in range(0, n):
print(inversions[i][j], end = " ")
print()
# Driver Code
# Given Input
n = 7
arr = [ 3, 6, 1, 6, 5, 3, 9 ]
# Function Call
findSubarrayInversions(arr, n)
# This code is contributed by amreshkumar3
Javascript
0 0 2 2 4 7 7
0 0 1 1 3 6 6
0 0 0 0 1 3 3
0 0 0 0 1 3 3
0 0 0 0 0 1 1
0 0 0 0 0 0 0
0 0 0 0 0 0 0
时间复杂度: O(N 2 )
空间复杂度: O(N 2 )
笔记-
- 通过在更大[][] 表之上构建前缀[][] 表可以节省一些空间,但顺序仍然保持不变。
- 如果您想找到所有子数组中反转的确切计数,因为子数组的数量始终为 O(N^2),因此不可能比 O(N^2) 执行得更好。