Given an array nums
, we call (i, j)
an important reverse pair if i < j
and nums[i] > 2*nums[j]
.
You need to return the number of important reverse pairs in the given array.
Example1:
Input: [1,3,2,3,1] Output: 2
Example2:
Input: [2,4,3,5,1] Output: 3
Note:
50,000
.Intuition
\nDo as directed in the question. We can simply check all the pairs if they are important reverse pairs or not.
\nAlgorithm
\nComplexity Analysis
\nTrivia
\nThe above code can be expressed as one-liner in Python:
\nPython
\n\nHerein, we iterate over all the pairs and store the boolean values for . Finally, we count the number of in the array and return the result.
\nIntuition
\nIn Approach #1, for each element , we searched the subarray for elements such that their value is greater than . In the previous approach, the search is linear. However, we need to make the process efficient. Maybe, memoization can help, but since, we need to compare the elements, we cannot find a linear DP solution.
\nObserve that the indices of the elements in subarray don\'t matter as we only require the count. So, we can sort the elements and perform binary search on the subarray. But, since the subarray keeps growing as we iterate to the next element, we need a data structure to store the previous result as well as to allow efficient searching(preferably ) - Binary Search Tree(BST) could be a good bet.
\nRefreshing BST
\nBST is a rooted binary tree, wherein each node is associated with a value and has 2 distinguishable sub-trees namely and subtree. The left subtree contains only the nodes with lower values than the parent\'s value, while the right subtree conatins only the nodes with greater values than the parent\'s value.
\nVoila!
\nThis is exactly what is required. So, if we store our elements in BST, then we can search the larger elements thus eliminating the search on smaller elements altogether.
\nAlgorithm
\nDefine the of BST that stores the and pointers to the and . We also need a count of elements(say ) in the subtree rooted at the current node that are greater than or equal to the current node\'s . is initialized to 1 for each node and , pointers are set to .
\nWe define the routine that recursively adds the given as an appropriate leaf node based on comparisons with the . Each time, the given is smaller than , we increment the and move the to the right subtree. While, if the is equal to the current , we simply increment the and exit. While, we move to the left subtree in case .
\nWe also require the routine that gives the count of number of elements greater than or equal to the . In the routine, if the is NULL, return 0. Otherwise, if , we know the count of values greater than or equal to the , hence simply return . In case, , the ans is calculated by adding and recursively calling the routine with . And if , ans is obtained by recursively calling the routine with .
\nNow, we can get to our main logic:
\nThe algorithm can be better understood using the example below:\n!?!../Documents/493_reverse_pairs.json:1000,662!?!
\n\nComplexity analysis
\nIntuition
\nThe problem with BST is that the tree can be skewed hence, making it in complexity. So, need a data structure that remains balanced. We could either use a Red-black or AVL tree to make a balanced BST, but the implementation would be an overkill for the solution. We can use BIT (Binary Indexed Tree, also called Fenwick Tree) to ensure that the complexity is with only 12-15 lines of code.
\nBIT Overview:
\nFenwick Tree or BIT provides a way to represent an array of numbers in an array(can be visualized as tree), allowing prefix/suffix sums to be calculated efficiently(). BIT allows to update an element in time.
\nWe recommend having a look at BIT from the following links before getting into details:
\nSo, BIT is very useful to accumulate information from front/back and hence, we can use it in the same way we used BST to get the count of elements that are greater than or equal to in the existing tree and then adding the current element to the tree.
\nAlgorithm
\nFirst, lets review the BIT and routines of BIT. According to the convention, routine goes from to , i.e., gives the sum for the range , and updates the values from current to the end of array. But, since, we require to find the numbers greater than the given index, as and when we update an index, we update all the ancestors of the node in the tree, and for , we go from the node to the end.
\nThe modified algorithm is:
\nupdate(BIT,index, val):\n while(index<0):\n BIT[index]+=val\n index-=(index&(-index))\n
Herein, we find get the next index using: , which is essentially subtracting the rightmost 1 from the binary representation. We update the previous indices since, if an element is greater than the index
\nAnd the modified algorithm is:
\nquery(BIT,index):\n sum=0\n while(index<BIT.size):\n sum+=BIT[index]\n index+=(index&(-index))\n
Herein, we find get the next index using: . This gives the suffix sum from to the end.
\nSo, the main idea is to count the number of elements greater than in range as we iterate from to . The steps are as follows:
\nComplexity analysis
\nIntuition
\nIn BIT and BST, we iterate over the array, dividing the array into 3 sections: already visited and hence added to the tree, current node and section to be visited. Another approach could be divide the problem into smaller subproblems, solving them and combining these problems to get the final result - Divide and conquer. We see that the problem has a great resemblance to the merge sort routine. The question is to find the inversions such that and . So, we can easily modify the merge sort to count the inversions as required.
\nMergesort
\nMergesort is a divide-and-conquer based sorting technique that operates in time. The basic idea to divide the array into several sub-arrays until each sub-array is single element long and merging these sublists recursively that results in the final sorted array.
\nAlgorithm
\nWe define routine that takes parameters an array say and and indices:
\nComplexity analysis
\nAnalysis written by @abhinavbansal0.
\nShoutout to @FUN4LEETCODE for the brilliant post!
\n