AfterAcademy Tech
•
01 May 2020

Difficulty: Medium
Asked in: Amazon, Google
Given an array of integers A[], if i < j and A[i] > A[j] then the pair (i, j) is called the inversion of an array A[]. You need to write a program to find the total counts of inversion in an array A[].
The inversion count of an array suggests how close the array is from being sorted. If the array is already sorted the inversion count in this case will be 0. Obviously, the inversion count will be maximum when the array is reversely sorted(descending order).
For Example:
Input: A[] = {3, 2, 1}
Output: 3
Explanation: The inversion pairs in the given array are (3,2), (3,1) and (2,1). Thus, the count of inversion is 3.
Input: A[] = {4, 1, 3, 2}
Output: 4
Explanation: There are four inversion pairs in the given array, (4,1), (4,3), (4,2) and (3,2). Thus, the inversion count is 4.
Possible questions to ask the interviewer:
You can try solving this problem here.
We are going to see four different solutions to this problem. The first one will be an obvious, brute force solution while in the second solution we will work on optimisation and come up with an efficient solution. The third solution will be based on using an ordered set and the fourth one will use the AVL tree to solve this problem.
Solution idea
The idea is very simple, we will start from the initial index and will traverse the entire array. While traversing the array for each index, we will find the number of elements which are smaller than it and are present in the right side of that element. That is for index i, we will look for smaller elements present from the index (i+1). With every such encounter of smaller elements, we will increase our counter. We will follow this approach for every element and at last, the value of the counter will be our inversion count.
Solution steps
index i, we will find the number of elements which are smaller than this element and are present on the right side of it.Pseudo-code
int inversionCount(int A[], int size)
{
int inversion_count = 0
for(i = 0 to size-2; i=i+1)
{
for(int j = i+1 to size-1; j=j+1)
{
if(A[j] < A[i])
inversion_count = inversion_count+1
}
}
return inversion_count
}
Complexity Analysis
Time Complexity: O(N²)
Space Complexity: O(1)
Critical ideas to think!
Solution idea
This solution idea is based on the divide and conquer algorithm. Here, we will be dividing our array into two halves similar as in the merge sort algorithm. For each half, we will be getting the inversion counts using recursion. The total counts of inversion will be the sum of inversions in the first half, second half as well as the inversion counts during the process of merging.
During the merge process, the inversion count is found by comparing elements of both the halves. We will use two pointers that will compare the indexes of both the array halves.
Getting inversion count during merge?
Suppose if the two halves of the array are like this: firstHalf[] = {2, 4, 7} and secondHalf[] = {1, 3, 6}. Now, the ith element(where i = 0) is greater than the corresponding jth element (j is also 0). Obviously, jth element will be smaller than all the rest elements of firstHalf array as this array is sorted. That is if 1 < 2, 1 will be smaller than 4 and 7 also.
Now, the inversion count, in this case, will be 3. Here the value of mid will be 3. So (mid-i) i.e. (3–0) will also give 3. So we always increment the inversion count by (mid-i) in such cases. This is how it works.

Solution steps
i will point to the starting element of the left half and j will point to the starting element of the second half. We will compare the elements at both the positions. If ith element is smaller than jth element just add it to the new sorted list. Else, increment the count of inversions by (mid-i).Pseudo-code
int merge(int originalArr[], int temp[], int start, int mid, int end)
{
int i = start;
int j = mid;
int k = start;
int inversion_count = 0;
while(i <= mid-1 && j<= end)
{
if(originalArr[i]< originalArr[j])
temp[k++] = originalArr[i++]
else{
inversion_count += mid-i;
temp[k++] = originalArr[j++]
}
}
while(i <= mid-1)
temp[k++] = originalArr[i++]
while(j <= end)
temp[k++] = originalArr[j++]
for(int i = start; i <= end; i++)
originalArr[i] = temp[i]
return inversion_count;
}
int mergeSort(int originalArr[], int temp[], int start, int end)
{
int inversion_count = 0;
if(start < end) {
int mid = (start+end)/2;
inversion_count += mergeSort(originalArr, temp, start, mid);
inversion_count += mergeSort(originalArr, temp, mid+1, end);
inversion_count += merge(originalArr, temp, start, mid+1, end);
}
return inversion_count;
}
int inversionCount(int A[], int size)
{
int temp[size]
return mergeSort(A, temp, 0, size-1)
}
Complexity Analysis
Time Complexity: O(NlogN)
Space Complexity: O(N) (Why?)
Solution idea
Here we will be using an ordered set where all the elements are stored in a sorted manner. The idea is, we will insert the first element into the set and then for every next element to be inserted we will find the first element's index that is larger than the current element(which is to be inserted). By getting the index of that just greater element we can find the distance between the two indices and add them to our inversion_count variable(that will store total inversion counts). We will keep doing this for all the elements. The value of inversion_count, at last, will be our final inversion count.
Solution steps
inversion_count to 0, which will store our inversion_count.inversion_count variable.inversion_count will be our desired output.Pseudo-code
int getUpperBound( ordered_set S, int elem)
{
//returns the upper bound for an element elem
}
int inversionCount(int A[], int size)
{
int ordered_set S
S.insert(A[0]) //Inserting first element into the set
inversion_count = 0
for(int i = 1 to size-1)
{
S.insert(A[i])
int firstGreaterElemIndex = getUpperBound(S, A[i])
inversion_count = inversion_count + (firstGreaterElemIndex-i)
}
return inversion_count
}
Complexity Analysis
Time Complexity: O(N^2)
Space Complexity: O(N)
Critical ideas to think!
Solution idea
The idea in this solution is to use a self-balancing Binary Search Tree(BST) like AVL or Red-Black Tree with augmentation to keep the size of the subtree in every node. With every insertion of a new node, we will traverse the array from start to end and keep adding the elements to the tree. Now if a > b where a appears before b in the array then obviously a will be in the right subtree. Whenever we will encounter any such node whose value is smaller than the root node's value, we will add this to the left node and increment the value of the inversion count with the number of elements present in the right subtree plus one for the root node. We are adding the size of right subtree as all elements of the right subtree will form a pair (elem, b) for element b where elem > b.
Solution steps
inversion_count by size of right subtree plus one.Pseudo-code
class avlNode
{
int value
avlNode left
avlNode right
int height
int size //size of the subtree
}
inversion_count = 0 //global variable
class avlTree
{
//root element of the tree
avlNode root
// constructor of the class
avlTree()
//creates a new node with value val
newNode(val)
//return height of the node
getHeight()
//returns size of the subtree
getSize()
insertNode(root, val)
{
if(root is NULL)
newNode(val)
if(root.val > val)
{
insertNode(root.left, val)
//inversion_count needs to be updated
inversion_count = inversion_count + getSize(root.right) + 1
}
else
{
insertNode(root.right, val)
}
//update height of the node
root.height = max(getHeight(root.left), getHeight(root.right)) + 1
//update size of the node
root.size = getSize(root.left) + getSize(root.right) + size + 1
//balance the tree if there is any imbalance
balance()
}
//insert node with value val to the tree
insert(val)
{
insertNode(root, val)
}
//balances the tree using rotations
balance()
//left rotation of the tree
rotateLeft()
//right rotation of the tree
rotateRight()
}
int inversionCount(int A[], int size)
{
for(int i = 0 to size-1)
{
avlTree avl_tree
avl_tree.insert(A[i], inversion_count)
}
return inversion_count
}
Complexity Analysis
Time Complexity: O(NlogN)
Space Complexity: O(N)
Critical ideas to think!

Happy Coding!
Team AfterAcademy!
AfterAcademy Tech
Given two integer array A[] and B[] of size m and n(n <= m) respectively. We have to check whether B[] is a subset of A[] or not. An array B is a subset of another array A if each element of B is present in A. (There are no repeated elements in both the arrays)

AfterAcademy Tech
This is an interview problem asked in companies like Google, Microsoft, Amazon. The problem is to remove duplicates from a sorted array or list.

AfterAcademy Tech
Given an array say A having n elements, the task is to sort the array in wavy manner. In wavy manner the array is in the form where A[0] >= A[1] <= A[2] >= A[3] <= A[4] >= …..

AfterAcademy Tech
Given two integer arrays A[] and B[] of size m and n, respectively. We need to find the intersection of these two arrays. The intersection of two arrays is a list of distinct numbers which are present in both the arrays. The numbers in the intersection can be in any order.
