Write a function to count the number of smaller elements on the right of each element in an array. Given an unsorted array arr[] of distinct integers, construct another array countSmaller[] such that countSmaller[i] contains the count of smaller elements on right side of element arr[i] in the array.
Examples:
Input : arr[] = {12, 1, 2, 3, 0, 11, 4}
Output : countSmaller[] = {6, 1, 1, 1, 0, 1, 0}
Input : arr[]={5, 4, 3, 2, 1}
Output :countSmaller[]={4, 3, 2, 1, 0}
In this post an easy implementation of https://www.geeksforgeeks.org/count-smaller-elements-on-right-side/ is discussed.
Create an empty Set in C++ STL (Note that Set in C++ STL is implemented using Self Balancing Binary Search Tree).
- Traverse the array element from i=len-1 to 0 and insert every element in a set.
- Find the first element that is lower than A[i] using lower_bound function.
- Find the distance between above found element and the beginning of the set using distance function.
- Store the distance in another array , Let’s say CountSmaller[ ].
- Print that array .
Implementation:
C++
#include <bits/stdc++.h>
using namespace std;
void countSmallerRight( int A[], int len)
{
set< int > s;
int countSmaller[len];
for ( int i = len - 1; i >= 0; i--) {
s.insert(A[i]);
auto it = s.lower_bound(A[i]);
countSmaller[i] = distance(s.begin(), it);
}
for ( int i = 0; i < len; i++)
cout << countSmaller[i] << " " ;
}
int main()
{
int A[] = {12, 1, 2, 3, 0, 11, 4};
int len = sizeof (A) / sizeof ( int );
countSmallerRight(A, len);
return 0;
}
|
Time Complexity: Note that the above implementation takes worst-case time complexity O(n^2) as the worst case time complexity of distance function is O(n) but the above implementation is very simple and works better than the naive algorithm in the average case.
Space Complexity: O(n),The space complexity of the above code is O(n). This is because we are using a set which takes O(n) space to store the elements.
Above approach works for unique elements but for duplicate elements just replace Set with Multiset.
Efficient Approach: Using policy based data structures in C++ STL.
Maintain a policy-based data structure of pairs just to resolve duplicate issues.
- We will travel the array from the end and every time we find the order_of_key of the current element to find the number of smaller elements to the right of it.
- Then we will insert the current element into our policy-based data structure.
Below is the implementation of the above approach:
C++
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#define pbds \
tree<pair< int , int >, null_type, less<pair< int , int > >, \
rb_tree_tag, tree_order_statistics_node_update>
using namespace __gnu_pbds;
using namespace std;
void countSmallerRight( int arr[], int n)
{
pbds s;
vector< int > ans;
for ( int i = n - 1; i >= 0; i--) {
if (i == n - 1) {
ans.push_back(0);
}
else {
ans.push_back(s.order_of_key({ arr[i], i }));
}
s.insert({ arr[i], i });
}
reverse(ans.begin(), ans.end());
for ( auto x : ans)
cout << x << " " ;
}
int main()
{
int n = 7;
int arr[] = { 12, 1, 2, 3, 0, 11, 4 };
countSmallerRight(arr, n);
return 0;
}
|
Time Complexity: O(N*LogN), where N is the number of elements in the given array. This is due to the fact that we are using a self-balancing binary search tree (PBDS) which has a time complexity of O(logN) for insertion and accessing the order statistic.
Space Complexity of the above algorithm is O(N) as we are using a self-balancing binary search tree to store the elements. We also use a vector to store the number of smaller elements to its right.