Count Inversions in an array | Set 1 (Using Merge Sort) | GeeksforGeeks

Count Inversions in an array | Set 1 (Using Merge Sort) | GeeksforGeeks


Count Inversions in an array | Set 1 (Using Merge Sort) | GeeksforGeeks

Explanation for the article: http://www.geeksforgeeks.org/counting

This video is contributed by Harshit Jain.


Content

0.59 -> Hello everyone!
1.59 -> And, welcome to GeeksforGeeks.
3.739 -> In this tutorial we are going to see how to count the number of inversions in an array.
9.1 -> First of all let us try to understand what do we mean by an inversion.
14.91 -> So an element at index I and element at index j form an inversion if the value of element
22.16 -> at index i is greater than value of element at index j whereas value of I is smaller than
29.71 -> value of j.
31.14 -> For example, in the given sequence 2,4,1,3,5 there are a total of 3 inversions.
38.86 -> Let us look at them one by one So first of all we look at elements 2 and
44.68 -> 1 highlighted in red.
47.19 -> Here 2 > 1 whereas index of 2 < index of 1.
53.44 -> So they form an inversion.
57.26 -> Similarly the element 4 and 1 form an inversion as 4 > 1 whereas index of 4 is smaller than
65.88 -> index of 1.
68.49 -> Finally we look at element 4 and 3.
71.7 -> They also form an inversion as 4 > 3 but index of 4 is smaller than index of 3.
79.409 -> In this problem we basically have to find out the inversion count of the array.
84.469 -> Inversion count actually tells how far or how close the array is from being sorted.
91.539 -> So if the array is completely sorted, there will not be any inversions in the array and
96.729 -> thus the inversion count will be zero.
99.469 -> However, if the array is sorted in reverse order, the inversion count will be the maximum
105.31 -> possible inversion count value for any array of that size.
111.34 -> First of all, letís look at the simplest method.
114.439 -> In this method we iterate over the array element by element and for each element we check the
120.73 -> number of smaller elements to the right of the selected element.
125.729 -> So you see the method getInvCount, we first of all initialize inv_count as zero.
131.12 -> Then we run a loop from 0 to n-1 where n is the total number of elements.
138.629 -> Then for each element, we run a loop from the element to itís right to element at index
146.069 -> n-1.
147.069 -> Whenever we encounter any element which is smaller than given element, we increment the
153.73 -> inv_count.
155.569 -> Finally we return the inv_count.
158.61 -> This method solves the problem in Order of n squared time complexity.
165.04 -> Now weíll look at the solution in which we will be using enhanced merge sort to count
169.88 -> the number of inversions in an array.
172.69 -> But firstly weíll quickly recapitulate the original merge sort algorithm.
178.15 -> Merge sort works on divide and conquer paradigm i.e. we keep recursively dividing the given
184.51 -> problem into smaller sub problems until they become simple enough to be solved directly,
190.739 -> then solutions of the subproblems are combined to give solution to the original problem.
198.03 -> Given an array, we first of all divide the array into two halves.
202.319 -> Then we call the mergeSort on each of those halves and then we finally merge those two
208.549 -> sorted subarrays.
211.829 -> Here is the big picture of enhanced merge sort algorithm.
215.56 -> We divide the array recursively into two halves and compute the answer for those two sub-halves.
222.799 -> Now suppose we know the number of inversions in the left and right halves of the array,
228.969 -> then what kinds of inversions are not accounted for in inv1 + inv2 ?
234.81 -> Well the answer is the ones we have to count during the merge step.
240.409 -> Therefore to get the total number of inversions we need to add number of inversions in the
245.779 -> left subarray, right subarray and in the merge step.
251.139 -> Now the question is how do we get the number of inversions in the merge operation?
256.37 -> To answer that let I be used for indexing left subarray and j be used for indexing right
263.59 -> subarray.
264.59 -> At any step in merge if value of element at index i is greater than value of element at
272.09 -> index j, then we know that there are (mid-i) inversions.
278.49 -> This is because both left and right subarrays are already sorted, so if element at index
284.83 -> i is greater than element at index j, then all the elements in the left subarray with
291.43 -> index greater than i will also be greater than element at index j.
299.06 -> Let us try to understand this with the help of an example.
302.05 -> So here you have the left and right half of the array.
307.06 -> Notice that both of these are already sorted individually.
311.96 -> So we start with index i=0 and index j =3 whereas the mid index is 3 because from index
320.06 -> 3 the right subarray starts.
323.419 -> Also the initial inversion count is set as Zero.
328.11 -> Now we compare the two highlighted elements.
331.58 -> 1 is smaller than 2, So we move it in the merged array and the inversion count remains
338.229 -> zero.
339.55 -> Now we compare 3 with 2.
342.22 -> As 3 is greater than 2, weíll move the smaller element i.e. 2 in the merged array.
348.47 -> But before that we see that we have encountered an inversion.
352.389 -> Although value of 3 is greater than value of 2, but the index of element 2 is smaller
358.65 -> than index of 3.
360.639 -> We already know that first subarray is sorted.
364.629 -> So elements coming after 3 will be greater than 3 and thus will also be greater than
369.69 -> value 2.
371.4 -> So they all form pairs of inversions with element 2.
375.78 -> So in total we see that there are mid index-i i.e. 3-1=2 inversions in this step.
384.55 -> So weíll increment the value of inversion count by 2.
389.05 -> Now we compare 3 with 4.
390.78 -> As 3 is smaller than 4, we move the value 3 to sorted array and increment the value
397.27 -> of i.
400.09 -> Now we compare 5 with 4.
402.919 -> Clearly 5 is greater than 4 but index of 5 is smaller than index of 4.
408.34 -> So we have again found an inversion.
413.07 -> As per our algorithm, weíll add mid index ñ i i.e. 3-2=1 inversions in the inversion
421.21 -> count.
422.3 -> After that weíll move 4 into the sorted array and increment the value of index j.
427.909 -> Now we compare 5 with 6.
429.99 -> As 5 is smaller than 6, we move the value 5 to sorted array.
436.75 -> Now as all the elements of left subarray are already processed, weíll just move the remaining
442.5 -> elements of right subarray to the sorted array.
446.6 -> After all elements are processed and moved to sorted merged array, we have the inversion
451.46 -> count of the merge step as 3.
455.699 -> Now letís understand the algorithm better with the help itís implementation.
460.56 -> So the implementation starts with the mergeSort function which takes as an argument the array
466.759 -> and itís size.
468.9 -> Inside this function, we create a temporary array and pass it to _mergesort method along
475.21 -> with the original array.
477.449 -> We also pass the starting and ending index of array i.e. 0 and array_size -1 respectively.
487.289 -> Now lets see the _mergeSort method.
491.189 -> Here we declare the variables mid and inv_count.
494.02 -> We also initialize the inversion count with value zero.
500.03 -> Here we check if right is greater than left, then we do the following.
505.67 -> We calculate the value of mid as right + left/2.
510.669 -> Now as per the algorithm, we call the _mergeSort method for left subarray and right subarray.
518.31 -> Notice that left subarray is from left to mid index whereas the right subarray is from
524.33 -> mid+1 to right.
527.23 -> We add the inversion counts returned by these respective calls to inv_count variable.
534.98 -> Finally we call the merge method to merge the left and right subarrays and add the inversion
540.57 -> count returned by _merge method to inv_count variable.
545.2 -> Lastly, we return the value of inv_count.
552.63 -> In merge method, we first of all declare variables i, j and k.
557.63 -> Then we declare inv_count and initialize it as zero.
563.03 -> Then we initialize variable i as left, j as mid and k as left.
570.64 -> Then while either one of the array is not completely processed, we do the following.
576.36 -> We compare the element at index i with element at index j.
581.31 -> If element at index i is smaller than or equal to element at index j, then we just copy the
588.18 -> element at index i to temp array and increment the values of k and i.
595.52 -> Otherwise we copy the value at index j to temp array and increment the value of both
602.14 -> k and j.
603.14 -> Additionally, as per the algorithm which we discussed, we encounter the inversions in
609.381 -> this case, so we add mid-i inversions to inv_count.
616.37 -> Once this is done, we copy the remaining elements of left subarray, if any, to temp array.
623.57 -> Then similarly we copy the remaining element of the right subarray, if any, to temp array.
630.13 -> Finally, copy the values from temp array back to our original array and return the inv_count
637.72 -> value.
639.26 -> Now coming to the time complexity.
641.47 -> The time complexity of this solution is same as of the merge sort algorithm i.e.
647.29 -> O(nlogn) and the algorithmic paradigm used is Divide and conquer.
653.86 -> So in total we discussed two methods to solve the problem.
658.23 -> The first one was simple method which solved the problem in Order of n squared time complexity
663.56 -> whereas the 2nd method using the enhanced merge sort solved the problem in Order of
669.79 -> n log n time complexity.
673.35 -> So that is all for this tutorial.
675.17 -> Thank you.

Source: https://www.youtube.com/watch?v=k9RQh21KrH8