Count smaller elements on right side
Write a function to count number of smaller elements on right of each element in an array. Given an unsorted array arr[] of distinct integers, construct another array countSmaller[] such that countSmaller[i] contains count of smaller elements on right side of each element arr[i] in array.
Examples:
Input: arr[] = {12, 1, 2, 3, 0, 11, 1}
Output: countSmaller[] = {6, 1, 2, 2, 0, 1, 0}
(Corner Cases)
Input: arr[] = {5, 4, 3, 2, 1}
Output: countSmaller[] = {4, 3, 2, 1, 0}
Input: arr[] = {1, 2, 3, 4, 5}
Output: countSmaller[] = {0, 0, 0, 0, 0}
Method 1 (Simple)
Use two loops. The outer loop picks all elements from left to right. The inner loop iterates through all the elements on right side of the picked element and updates countSmaller[].
void constructLowerArray (int *arr[], int *countSmaller, int n)
{
int i, j;
// initialize all the counts in countSmaller array as 0
for (i = 0; i < n; i++)
countSmaller[i] = 0;
for (i = 0; i < n; i++)
{
for (j = i+1; j < n; j++)
{
if (arr[j] < arr[i])
countSmaller[i]++;
}
}
}
/* Utility function that prints out an array on a line */
void printArray(int arr[], int size)
{
int i;
for (i=0; i < size; i++)
printf("%d ", arr[i]);
printf("\n");
}
// Driver program to test above functions
int main()
{
int arr[] = {12, 10, 5, 4, 2, 20, 6, 1, 0, 2};
int n = sizeof(arr)/sizeof(arr[0]);
int *low = (int *)malloc(sizeof(int)*n);
constructLowerArray(arr, low, n);
printArray(low, n);
return 0;
}
Time Complexity: O(n^2)
Auxiliary Space: O(1)
Method 2 (Use Self Balancing BST)
A Self Balancing Binary Search Tree (AVL, Red Black,.. etc) can be used to get the solution in O(nLogn) time complexity. We can augment these trees so that every node N contains size the subtree rooted with N. We have used AVL tree in the following implementation.
We traverse the array from right to left and insert all elements one by one in an AVL tree. While inserting a new key in an AVL tree, we first compare the key with root. If key is greater than root, then it is greater than all the nodes in left subtree of root. So we add the size of left subtree to the count of smaller element for the key being inserted. We recursively follow the same approach for all nodes down the root.
Following is C implementation.
#include<stdio.h>
#include<stdlib.h>
// An AVL tree node
struct node
{
int key;
struct node *left;
struct node *right;
int height;
int size; // size of the tree rooted with this node
};
// A utility function to get maximum of two integers
int max(int a, int b);
// A utility function to get height of the tree rooted with N
int height(struct node *N)
{
if (N == NULL)
return 0;
return N->height;
}
// A utility function to size of the tree of rooted with N
int size(struct node *N)
{
if (N == NULL)
return 0;
return N->size;
}
// A utility function to get maximum of two integers
int max(int a, int b)
{
return (a > b)? a : b;
}
/* Helper function that allocates a new node with the given key and
NULL left and right pointers. */
struct node* newNode(int key)
{
struct node* node = (struct node*)
malloc(sizeof(struct node));
node->key = key;
node->left = NULL;
node->right = NULL;
node->height = 1; // new node is initially added at leaf
node->size = 1;
return(node);
}
// A utility function to right rotate subtree rooted with y
struct node *rightRotate(struct node *y)
{
struct node *x = y->left;
struct node *T2 = x->right;
// Perform rotation
x->right = y;
y->left = T2;
// Update heights
y->height = max(height(y->left), height(y->right))+1;
x->height = max(height(x->left), height(x->right))+1;
// Update sizes
y->size = size(y->left) + size(y->right) + 1;
x->size = size(x->left) + size(x->right) + 1;
// Return new root
return x;
}
// A utility function to left rotate subtree rooted with x
struct node *leftRotate(struct node *x)
{
struct node *y = x->right;
struct node *T2 = y->left;
// Perform rotation
y->left = x;
x->right = T2;
// Update heights
x->height = max(height(x->left), height(x->right))+1;
y->height = max(height(y->left), height(y->right))+1;
// Update sizes
x->size = size(x->left) + size(x->right) + 1;
y->size = size(y->left) + size(y->right) + 1;
// Return new root
return y;
}
// Get Balance factor of node N
int getBalance(struct node *N)
{
if (N == NULL)
return 0;
return height(N->left) - height(N->right);
}
// Inserts a new key to the tree rotted with node. Also, updates *count
// to contain count of smaller elements for the new key
struct node* insert(struct node* node, int key, int *count)
{
/* 1. Perform the normal BST rotation */
if (node == NULL)
return(newNode(key));
if (key < node->key)
node->left = insert(node->left, key, count);
else
{
node->right = insert(node->right, key, count);
// UPDATE COUNT OF SMALLER ELEMENTS FOR KEY
*count = *count + size(node->left) + 1;
}
/* 2. Update height and size of this ancestor node */
node->height = max(height(node->left), height(node->right)) + 1;
node->size = size(node->left) + size(node->right) + 1;
/* 3. Get the balance factor of this ancestor node to check whether
this node became unbalanced */
int balance = getBalance(node);
// If this node becomes unbalanced, then there are 4 cases
// Left Left Case
if (balance > 1 && key < node->left->key)
return rightRotate(node);
// Right Right Case
if (balance < -1 && key > node->right->key)
return leftRotate(node);
// Left Right Case
if (balance > 1 && key > node->left->key)
{
node->left = leftRotate(node->left);
return rightRotate(node);
}
// Right Left Case
if (balance < -1 && key < node->right->key)
{
node->right = rightRotate(node->right);
return leftRotate(node);
}
/* return the (unchanged) node pointer */
return node;
}
// The following function updates the countSmaller array to contain count of
// smaller elements on right side.
void constructLowerArray (int *arr[], int countSmaller[], int n)
{
int i, j;
struct node *root = NULL;
// initialize all the counts in countSmaller array as 0
for (i = 0; i < n; i++)
countSmaller[i] = 0;
// Starting from rightmost element, insert all elements one by one in
// an AVL tree and get the count of smaller elements
for (i = n-1; i >= 0; i--)
{
root = insert(root, arr[i], &countSmaller[i]);
}
}
/* Utility function that prints out an array on a line */
void printArray(int arr[], int size)
{
int i;
printf("\n");
for (i=0; i < size; i++)
printf("%d ", arr[i]);
}
// Driver program to test above functions
int main()
{
int arr[] = {10, 6, 15, 20, 30, 5, 7};
int n = sizeof(arr)/sizeof(arr[0]);
int *low = (int *)malloc(sizeof(int)*n);
constructLowerArray(arr, low, n);
printf("Following is the constructed smaller count array");
printArray(low, n);
return 0;
}
Time Complexity: O(nLogn)
Auxiliary Space: O(n)
Please write comments if you find anything incorrect, or you want to share more information about the topic discussed above.
You may also like following posts
use of stack will give O(n) solution. this problem is same as finding first larger number on left
@pankaj: Use of stacks seems like a promising idea. Could you please provide more details of algorithm.
Your program didn't give right answer to the following input:
12 1 2 3 0 11 1
Your program produced:
6 2 2 2 0 1 0
whereas the right output is:
6 1 2 2 0 1 0
could you please notify me by email with your answer , this would help me a lot
thank you
@Ali: Take a closer look at the problem statement. It says distinct integers. The example given by you is not a valid one.
This problem can also be solved by using Binary Indexed Tree.
how can we modify the above method 2 to get the sum of smaller elements on the right?
I think in the insert function , instead of doing coun+=size(node->left) , we need to traverse the left subtree and add the node values. Is there any better way?
Thanks.
#include <stdio.h> int main() { int a[20],i,n,j,count[20]; for(i=0;i<n;i++) { count[i]=0; } printf("Enter the no of no's"); scanf("%d",&n); printf("Enter the no's"); for(i=0;i<n;i++) { scanf("%d",&a[i]); } for(i=0;i<n;i++) { for(j=i+1;j<n;j++) { if(a[i]>a[j]) { count[i]++; } } } for(i=0;i<n;i++) { printf("%d",count[i]); } return 0; }for the second method, can it be done by some in-build data structure in cpp as priority queue,etc?
Thanks.
@Vinothkumar and @PsychoCoder:
There were problems in the original version of the second method. We have updated it with the correct version. We have also added code for the same.
can anyone explain the second method with example?
In the 1st example for Method 2.
12 -> 2 -> 1
makes a rearrangement. Before rearrangement the left subtree count of 12 is 2. So after rearrangement will it be 0 ??
#include
void rightsmaller(int a[])
{
int count[20]={0},i=0,j=0;
count[0]=0;
for( i=0;i0)
{
for(j=0;j<i;j++)
{
if(a[j]<a[i])
{
count[i]++;
}
}
}
}
// display the array count
for(i=0;i<8;i++)
printf("%d ",count[i]);
}
int main()
{
int array[]={2,1,3,4,6,1,9,8};
rightsmaller(array);
}
@Rahul Sharm: Could you please post the code again within the sourcecode tags
we can even do this with a simple recursive method right
public int numSmaller(int[] elements, int position){ if(position == (elements.length-1)){ return 0; } return numSmaller(int[] elements, position+1) + isMin(int[] elements, position); } public int isMin(int elements[], int presentPosition){ if(elements[presentPosition] > elements[presentPosition+1]){ return 1; } return 0; }Time Complexity will be O(n)
Your second algorithm is wrong as per the question.
Questions says smaller elements to the right, not all smaller elements.
@Sanju: Please take a closer look at the algorithm. After finding smaller elements for an elemenet, we delete the element from tree. By Deletion, we make sure that this node is not considered when we are processing elements to its right.
can someone explain the approach with an example ?
Second case source code
pass the following parameters
arr=input arr;
min=array where the value to be stored
n=size of array arr
typedef struct node { int data; node *left,*right; int small; }; void fun(int arr[],int mins[],int n) { node *root=NULL; for(int i=n-1;i>=0;i--) { int num=arr[i]; if(root==NULL) //to check if root tree //exist or not,executed only once { root=new node; root->data=num; root->left=root->right=NULL; root->small=0; mins[i]=0; } else { node *mover=root; int count=0; while(1) { if((mover->data)<num) { //if the value is bigger at the current node into count count++; //add the number of nodes which are smaller then current node count+=mover->small; if(mover->right!=NULL) mover=mover->right; else break; } else { mover->small=mover->small+1; //add one more node in the number of "small nodes" if(mover->left!=NULL) mover=mover->left; else break; } } node *x= new node; x->data=arr[i]; x->left=x->right=NULL; x->small=0; if((mover->data)<num) mover->right=x; else mover->left=x; mins[i]=count; } } }i guess your tree isn't balance .......... so at the worst case scenario complexity will be again O(0logN).......... however it can be improved using AVL tree .... i had tried and its working fine but code is too lengthy ..............
i mean to say complexity will be O(n2) not O(nlogn)
yup..for skewed trees it would be O(n^2)
you can first sort the array which can be done in O(nlogn) and after that fill the countsmaller array with the value=n-index of element in count smaller array.
one thing that need to be kept in mind that if the array is containing the duplicate elements that an additional check is also required to account that.but that also can be done in O(n).
so overall complexity would be O(nlogn).
Looks like you didn't get the question. It is not about all smaller elements, but elements only on the right side.
A good example that shows use of self balancing BSTs.
Can somebody please share the code for method 2?