http://www.geeksforgeeks.org/count-inversions-in-an-array-set-2-using-self-balancing-bst/
http://www.geeksforgeeks.org/count-inversions-in-an-array-set-2-using-self-balancing-bst/
Auxiliary space : O(maxElement)
Count Inversions in an array | GeeksforGeeks
Time Complexity of the Naive approach is O(n2) and that of merge sort based approach is O(n Log n). In this post one more O(n Log n) approach is discussed. The idea is to use Self-Balancing Binary Search Tree like Red-Black Tree, AVL Tree, etc and augment it so that every node also keeps track of number of nodes in right subtree.
1) Create an empty AVL Tree. The tree is augmented here such that every node also maintains size of subtree rooted with this node. 2) Initialize inversion count or result as 0. 3) Iterate from 0 to n-1 and do following for every element in arr[i] a) Insert arr[i] into the AVL Tree. The insertion operation also updates result. The idea is to keep counting greater nodes when tree is traversed from root to a leaf for insertion. 4) Return result.
More explanation for step 3.a:
1) When we insert arr[i], elements from arr[0] to arr[i-1] are already inserted into AVL Tree. All we need to do is count these nodes.
2) For insertion into AVL Tree, we traverse tree from root to a leaf by comparing every node with arr[i[]. When arr[i[ is smaller than current node, we increase inversion count by 1 plus the number of nodes in right subtree of current node. Which is basically count of greater elements on left of arr[i], i.e., inversions.
1) When we insert arr[i], elements from arr[0] to arr[i-1] are already inserted into AVL Tree. All we need to do is count these nodes.
2) For insertion into AVL Tree, we traverse tree from root to a leaf by comparing every node with arr[i[]. When arr[i[ is smaller than current node, we increase inversion count by 1 plus the number of nodes in right subtree of current node. Which is basically count of greater elements on left of arr[i], i.e., inversions.
// An AVL tree node
struct
Node
{
int
key, height;
struct
Node *left, *right;
int
size;
// size of the tree rooted with this Node
};
// A utility function to get height of the tree rooted with N
int
height(
struct
Node *N)
{
if
(N == NULL)
return
0;
return
N->height;
}
// A utility function to size of the tree of rooted with N
int
size(
struct
Node *N)
{
if
(N == NULL)
return
0;
return
N->size;
}
/* Helper function that allocates a new Node with the given key and
NULL left and right pointers. */
struct
Node* newNode(
int
key)
{
struct
Node* node =
new
Node;
node->key = key;
node->left = node->right = NULL;
node->height = node->size = 1;
return
(node);
}
// A utility function to right rotate subtree rooted with y
struct
Node *rightRotate(
struct
Node *y)
{
struct
Node *x = y->left;
struct
Node *T2 = x->right;
// Perform rotation
x->right = y;
y->left = T2;
// Update heights
y->height = max(height(y->left), height(y->right))+1;
x->height = max(height(x->left), height(x->right))+1;
// Update sizes
y->size = size(y->left) + size(y->right) + 1;
x->size = size(x->left) + size(x->right) + 1;
// Return new root
return
x;
}
// A utility function to left rotate subtree rooted with x
struct
Node *leftRotate(
struct
Node *x)
{
struct
Node *y = x->right;
struct
Node *T2 = y->left;
// Perform rotation
y->left = x;
x->right = T2;
// Update heights
x->height = max(height(x->left), height(x->right))+1;
y->height = max(height(y->left), height(y->right))+1;
// Update sizes
x->size = size(x->left) + size(x->right) + 1;
y->size = size(y->left) + size(y->right) + 1;
// Return new root
return
y;
}
// Get Balance factor of Node N
int
getBalance(
struct
Node *N)
{
if
(N == NULL)
return
0;
return
height(N->left) - height(N->right);
}
// Inserts a new key to the tree rotted with Node. Also, updates
// *result (inversion count)
struct
Node* insert(
struct
Node* node,
int
key,
int
*result)
{
/* 1. Perform the normal BST rotation */
if
(node == NULL)
return
(newNode(key));
if
(key < node->key)
{
node->left = insert(node->left, key, result);
// UPDATE COUNT OF GREATE ELEMENTS FOR KEY
*result = *result + size(node->right) + 1;
}
else
node->right = insert(node->right, key, result);
/* 2. Update height and size of this ancestor node */
node->height = max(height(node->left),
height(node->right)) + 1;
node->size = size(node->left) + size(node->right) + 1;
/* 3. Get the balance factor of this ancestor node to
check whether this node became unbalanced */
int
balance = getBalance(node);
// If this node becomes unbalanced, then there are
// 4 cases
// Left Left Case
if
(balance > 1 && key < node->left->key)
return
rightRotate(node);
// Right Right Case
if
(balance < -1 && key > node->right->key)
return
leftRotate(node);
// Left Right Case
if
(balance > 1 && key > node->left->key)
{
node->left = leftRotate(node->left);
return
rightRotate(node);
}
// Right Left Case
if
(balance < -1 && key < node->right->key)
{
node->right = rightRotate(node->right);
return
leftRotate(node);
}
/* return the (unchanged) node pointer */
return
node;
}
// The following function returns inversion count in arr[]
int
getInvCount(
int
arr[],
int
n)
{
struct
Node *root = NULL;
// Create empty AVL Tree
int
result = 0;
// Initialize result
// Starting from first element, insert all elements one by
// one in an AVL tree.
for
(
int
i=0; i<n; i++)
// Note that address of result is passed as insert
// operation updates result by adding count of elements
// greater than arr[i] on left of arr[i]
root = insert(root, arr[i], &result);
return
result;
}
BIT basically supports two operations for an array arr[] of size n:
- Sum of elements till arr[i] in O(Log n) time.
- Update an array element in O(Log n) time.
BIT is implemented using an array and works in form of trees. Note that there are two ways of looking at BIT as a tree.
- The sum operation where parent of index x is "x - x(x & -x)".
- The update operation where parent of index x is "x + x(x & -x)".
We recommend you refer Binary Indexed Tree (BIT) before further reading this post.
Basic Approach using BIT of size Θ(maxElement):
The idea is to iterate the array from n-1 to 0. When we are at i'th index, we check how many numbers less than arr[i] are present in BIT and add it to the result. To get the count of smaller elements, getSum() of BIT is used. In his basic idea, BIT is represented as an array of size equal to maximum element plus one. So that elements can be used as an index.
After that we add current element to to the BIT[] by doing an update operation that updates count of current element from 0 to 1, and therefore updates ancestors of current element in BIT (See update() in BIT for details).
Time Complexity :- The update function and getSum function runs for O(log(maximumelement)) and we are iterating over n elements. So overall time complexity is : O(nlog(maximumelement)).The idea is to iterate the array from n-1 to 0. When we are at i'th index, we check how many numbers less than arr[i] are present in BIT and add it to the result. To get the count of smaller elements, getSum() of BIT is used. In his basic idea, BIT is represented as an array of size equal to maximum element plus one. So that elements can be used as an index.
After that we add current element to to the BIT[] by doing an update operation that updates count of current element from 0 to 1, and therefore updates ancestors of current element in BIT (See update() in BIT for details).
Auxiliary space : O(maxElement)
// Returns sum of arr[0..index]. This function assumes
// that the array is preprocessed and partial sums of
// array elements are stored in BITree[].
int
getSum(
int
BITree[],
int
index)
{
int
sum = 0;
// Initialize result
// Traverse ancestors of BITree[index]
while
(index > 0)
{
// Add current element of BITree to sum
sum += BITree[index];
// Move index to parent node in getSum View
index -= index & (-index);
}
return
sum;
}
// Updates a node in Binary Index Tree (BITree) at given index
// in BITree. The given value 'val' is added to BITree[i] and
// all of its ancestors in tree.
void
updateBIT(
int
BITree[],
int
n,
int
index,
int
val)
{
// Traverse all ancestors and add 'val'
while
(index <= n)
{
// Add 'val' to current node of BI Tree
BITree[index] += val;
// Update index to that of parent in update View
index += index & (-index);
}
}
// Returns inversion count arr[0..n-1]
int
getInvCount(
int
arr[],
int
n)
{
int
invcount = 0;
// Initialize result
// Find maximum element in arr[]
int
maxElement = 0;
for
(
int
i=0; i<n; i++)
if
(maxElement < arr[i])
maxElement = arr[i];
// Create a BIT with size equal to maxElement+1 (Extra
// one is used so that elements can be directly be
// used as index)
int
BIT[maxElement+1];
for
(
int
i=1; i<=maxElement; i++)
BIT[i] = 0;
// Traverse all elements from right.
for
(
int
i=n-1; i>=0; i--)
{
// Get count of elements smaller than arr[i]
invcount += getSum(BIT, arr[i]-1);
// Add current element to BIT
updateBIT(BIT, maxElement, arr[i], 1);
}
return
invcount;
}
Better Approach using BIT of size Θ(n):
The problem with the previous approach is that it doesn't work for negative numbers as index cannot be negative. Also by updating the value till maximum element we waste time and space as it is quite possible that we may never use intermediate value. For example, lots of space an time is wasted for an array like {1, 100000}.
The problem with the previous approach is that it doesn't work for negative numbers as index cannot be negative. Also by updating the value till maximum element we waste time and space as it is quite possible that we may never use intermediate value. For example, lots of space an time is wasted for an array like {1, 100000}.
The idea is to convert given array to an array with values from 1 to n and relative order of smaller and greater elements remains
Example :- arr[] = {7, -90, 100, 1} It gets converted to, arr[] = {3, 1, 4 ,2 } as -90 < 1 < 7 < 100.
We only have to make BIT[] of number of elements instead of maximum element.
Changing element will not have any change in the answer as the greater elements remain greater and at same position.
Changing element will not have any change in the answer as the greater elements remain greater and at same position.
Time Complexity :- The update function and getSum function runs for O(log(n)) and we are iterating over n elements. So overall time complexity is : O(nlogn).
Auxiliary space : O(n)
Auxiliary space : O(n)
// 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 arrp[] 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 inversion count arr[0..n-1]
int
getInvCount(
int
arr[],
int
n)
{
int
invcount = 0;
// Initialize result
// 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);
// Create a BIT with size equal to maxElement+1 (Extra
// one is used so that elements can be directly be
// used as index)
int
BIT[n+1];
for
(
int
i=1; i<=n; i++)
BIT[i] = 0;
// Traverse all elements from right.
for
(
int
i=n-1; i>=0; i--)
{
// Get count of elements smaller than arr[i]
invcount += getSum(BIT, arr[i]-1);
// Add current element to BIT
updateBIT(BIT, n, arr[i], 1);
}
return
invcount;
}