Advertisement
imashutosh51

Count of smaller number after self

Oct 29th, 2022
50
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 7.65 KB | None | 0 0
  1. /*
  2. basic idea:
  3. we do a normal merge sort
  4.  
  5. whenever we merge 2 small sub-arrays into 1 bigger result array
  6. the standard merge algorithm is already checking for cases which this coding problem is asking for
  7. the standard merge algorithm already checks for numbers positioned to the right of the current element, that are smaller than the current element
  8. example:
  9. The example given in the problem's description: [5, 2, 6, 1]
  10. Let us do normal merge sort on this given array.
  11.  
  12. First, just as normal merge sort, we
  13.  
  14. recursively split array
  15. go top-down until each sub-array is of size 1
  16. [5, 2, 6, 1]
  17. [5, 2] [6, 1]
  18. [5] [2] [6] [1]
  19.  
  20. Now, we go back bottom-up.
  21. We merge [5] and [2] into a result array
  22. Normally we just
  23.  
  24. compare the first element of both sub-arrays (5 and 2)
  25. take smaller element (2)
  26. put smaller element into the "merged" area (now holding only 2)
  27. NOTICE: in this case, we know that:
  28.  
  29. before the sort, all elements in the left sub-array [5], are orginally positioned LEFT of all elements in the right sub-array [2]
  30.  
  31. 5 > 2
  32.  
  33. Now we have found 1 instance, of an element (2), that is positioned to the right side of 5, and smaller than 5
  34.  
  35. We can increment by 1, the answer result count for 5
  36.  
  37. If we repeat this process, we will have answer result counts for all elements, which is the answer the coding problem is asking for
  38.  
  39. For the rest of the explanation, I will use this notation to describe the answer result count:
  40. 5(3) 2(0) 6(1) 1(0)
  41.  
  42. In this example for notation only, for the original input element 5, there are 3 elements to the right side of 5, that are smaller than 5.
  43.  
  44. Let's continue on our original example, from the problem description:
  45.  
  46. [5, 2, 6, 1]
  47. [5, 2] [6, 1]
  48. [5] [2] [6] [1]
  49.  
  50. result count:
  51. 5(0) 2(0) 6(0) 1(0)
  52.  
  53. if we merge up one level from the bottom
  54.  
  55. 2 is smaller than, and to the right of 5 ==> increment count for 5
  56. 1 is smaller than, and to the right of 6 ==> increment count for 6
  57. [5, 2, 6, 1]
  58. [2, 5] [1, 6]
  59.  
  60. result count:
  61. 5(1) 2(0) 6(1) 1(0)
  62.  
  63. Now we have to merge:
  64.  
  65. left sub-array, [2, 5]
  66. right sub-array [1, 6]
  67. Notice that
  68.  
  69. all elements in right sub-array, are originally positioned to the right, of all elements in the left sub-array
  70. Notice that 1, from the right sub-array, is less than 2 from the left sub-array.
  71. That means 1 is positioned right of 2, and smaller than 2
  72. So we should increment answer result count for 2
  73.  
  74. Notice that 1 is also less than 5, and positioned to the right of 5
  75.  
  76. In fact, 1 is less than, and positioned to the right of, all elements in the left-subarray after the element 2
  77.  
  78. this is because the left sub-array was already sorted from previous recursion merge-sort calls.
  79.  
  80. in this example, it would be:
  81. 1 < 2 < 5
  82.  
  83. so we will also need to increment the answer result count for 5
  84.  
  85. this is the updated state:
  86.  
  87. [5, 2, 6, 1]
  88. [2, 5] [1, 6] ----------> [2, 5] [6] + merged= [1]
  89.  
  90. result count:
  91. 5(1) 2(0) 6(1) 1(0) -------> 5(2) 2(1) 6(1) 1(0)
  92.  
  93. now, the only element in the right sub-array is 6. The elements in the left sub-array, [2, 5], are all smaller than 6. They are not what the problem is looking for, so just move them to the "merged" area, same as normal merge sort.
  94.  
  95. [5, 2, 6, 1]
  96. [2, 5] [1, 6] ----------> merged= [1,2,5,6]
  97.  
  98. result count:
  99. 5(1) 2(0) 6(1) 1(0) -------> 5(2) 2(1) 6(1) 1(0)
  100.  
  101. Merge sort is done now.
  102. The final answer result count is [2,1,1,0], same as in the problem description
  103.  
  104. Since we just did a normal merge sort, and added some checking logic along the way, the runtime is same as normal merge sort, O(n log n)
  105.  
  106. additional issue
  107. take this example:
  108.  
  109. left-subarray: [9, 11, 15]
  110. right-subarray: [2, 5, 6]
  111. merged: [ ]
  112.  
  113. say we are merging these 2 sub-arrays into 1 result array.
  114. In a normal merge, this is O(n).
  115. We compare the heads of the 2 subarray, find the smaller, and move it to merged area
  116. repeat one by one
  117.  
  118. But for this coding problem, 2 is smaller than 9, and to the right of 9. We know that 2 is also smaller than, and to the right of, every element in left sub-array after 9
  119.  
  120. If we increment the answer result count for 9, and then
  121. increment the answer result count for 11, and then
  122. increment the answer result count for 15, then
  123. we just did 3 operations (basically traversed the whole left sub array).
  124.  
  125. Ok now 2 is handled. We move 2 to the merged area. Now we process 5
  126. We compare 5 and 9. Same thing happens. We again have to increment the answer result count for 9, 11, and 15.
  127.  
  128. Now we process 6. Same thing again, increment the answer result count for 9, 11, and 15.
  129.  
  130. So the operation for merging the left and right sub-arrays, becomes O(N^2), instead of the usual O(N) merge for normal merge sort.
  131.  
  132. We can avoid this slowness, by keeping a count, of the number of elements moved from the right sub-array to the merged area. Let's call this count "numElemsRightArrayLessThanLeftArray"
  133.  
  134. In our example
  135.  
  136. left-subarray: [9, 11, 15]
  137. right-subarray: [2, 5, 6]
  138. merged: [ ]
  139. numElemsRightArrayLessThanLeftArray: 0
  140.  
  141. Here are the steps we take:
  142.  
  143. compare 2 and 9
  144. 2 is less than 9 and positioned right side of 9
  145. DO NOT increment anwer result count for 9
  146. increment numElemsRightArrayLessThanLeftArray
  147. move 2 to "merged" area
  148. repeat for 5
  149. increment numElemsRightArrayLessThanLeftArray
  150. move 5 to "merged" area
  151. repeat for 6
  152. increment numElemsRightArrayLessThanLeftArray
  153. move 6 to "merged" area
  154. the state is now:
  155.  
  156. left-subarray: [9, 11, 15]
  157. right-subarray: []
  158. merged: [2, 5, 6]
  159. numElemsRightArrayLessThanLeftArray: 3
  160. result count: 9(0) 11(0) 15(0)
  161.  
  162. numElemsRightArrayLessThanLeftArray is 3. This indicates there are currently 3 elements less than 9, that are to the right side of 9
  163.  
  164. next step, right side sub-array is empty. Move all elements in left sub-array to "merged" area.
  165. Since
  166. numElemsRightArrayLessThanLeftArray = 3,
  167. we add 3 to the answer result counts of 9, and move 9 to the "merged" area.
  168. We repeat for elements 11 and 15
  169.  
  170. result count: 9(3) 11(3) 15(3)
  171.  
  172. This makes the the merge operation O(N) as usual for merge sort. We avoid O(N^2)
  173.  
  174. Inversions
  175. some other discussion explanation threads mention the word "inversion" a lot, but don't really explain what it is, or how it relates to this problem
  176.  
  177. an inversion is a Pair of Numbers, in an array, where the left number is bigger than the right number
  178.  
  179. example:
  180. 2, 9, 6
  181.  
  182. the pair of numbers (9, 6) is an inversion.
  183.  
  184. the pair (2, 9) is NOT and inversion
  185.  
  186. So, in a sorted array
  187. 2, 6, 9
  188.  
  189. there are 0, no inversions
  190.  
  191. but an reverse-sorted array has the max number of inversions:
  192. 9, 6, 2
  193. */
  194.  
  195. void merge(vector <pair<int,pair<int,int>>> &arr,int l,int mid,int r){
  196.     int i=l,j=mid+1;
  197.     int cur=0;
  198.     vector <pair<int,pair<int,int>>> temp;
  199.     while(i<=mid && j<=r){
  200.         if(arr[j].first<arr[i].first){ cur++; temp.push_back(arr[j++]);}
  201.         else{
  202.             arr[i].second.second+=cur;
  203.             temp.push_back(arr[i++]);
  204.         }
  205.     }
  206.     while(i<=mid){
  207.         arr[i].second.second+=cur;
  208.         temp.push_back(arr[i++]);
  209.     }
  210.     while(j<=r){
  211.         temp.push_back(arr[j++]);
  212.     }
  213.     int k=0;
  214.     for(int i=l;i<=r;i++){
  215.         arr[i]=temp[k++];
  216.     }
  217. }
  218. void merge_sort(vector <pair<int,pair<int,int>>> &arr,int l,int r){
  219.     if(l<r){
  220.         int mid=(l+r)/2;
  221.         merge_sort(arr,l,mid);
  222.         merge_sort(arr,mid+1,r);
  223.         merge(arr,l,mid,r);
  224.     }
  225. }
  226.  
  227. class Solution{
  228. public:
  229.     vector<int> constructLowerArray(int *nums, int n) {
  230.         vector <pair<int,pair<int,int>>> arr;
  231.         for(int i=0;i<n;i++){
  232.             arr.push_back({*(nums+i),{i,0}});
  233.         }
  234.         merge_sort(arr,0,n-1);
  235.         vector <int> res(n,0);
  236.         for(auto itr:arr){
  237.             res[itr.second.first]=itr.second.second;
  238.         }
  239.         return res;
  240.     }
  241. };
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement