C int array sort - c

If I have an int[3] array like such:
score_list[3] = [ 1, 2, 0]
Where each location in the array corresponds to a specific Document Number:
score_list[0] = D1
score_list[1] = D2
score_list[2] = D3
What would be the easiest way to sort the array in Descending order, keeping track of the place of each moved int
Where (after sort):
score_list[3] = [ 2, 1, 0]
And
score_list[0] = D2
score_list[1] = D1
score_list[2] = D3
I only need to print in descending order, not actually rearrange the int array, so:
for (int i=0; i<3; i++)
{
if (score_list[0] > score_list[1] && score_list[2])
printf("D%d-%d",i, score_list[0]);
if (score_list[1] > score_list[0] && score_list[2])
printf("D%d-%d", i, score_list[1]);
if (score_list[2] > score_list[0] && score_list[1])
printf("D%d-%d", i, score_list[2]);
}
Would print the highest number first, then I would compare the last 2, I just feel like this takes too long and there must be a more efficient way

You can solve this using marker (interface) design pattern.
By keeping a record of the visited index in your array each time you get the max, let me define the solution structure first then I will walk through it:
Make a new array of the same size of the score_list, let's call that array marker
In the for loop, you will make another loop to check for max score and in the same time check to see if the location of the max score in the marker array is 0.
Sample run:
On i=0
Loop on the score_list, and find the max score with marker == 0, print it and then put marker for that score = 1.
On i=1
You will do the same but now there is one location excluded from the list
Here you are a sample code how to do it:
Note that: this code is not a runnable one (and it is not optimized too O(n^2)), I wrote it for explanation purposes only.
int max = -1;
int doc = -1;
int marker[3] = {0, 0, 0};
for (i=0; i<3; i++)
{
max = -1;
for (j=0; j<3; j++)
{
// skip this location if it is already printed
if (marker[j] == 1)
continue;
if (score_list[j] > max)
{
doc = j;
max = score_list[j];
}
}
// this doc will not appear again in the inner for loop (j-loop)
marker[doc] = 1;
// print the document with the score
printf("D%d-%d",doc, max);
}

Related

Check if a string is included in an array and append if not (C)

I have 2 arrays, one called 'edges' which contains a list of city names and another called cityNames which is initialised as an empty string.
What I would like to do is move through the edges array element by element and see if it is included in the cityNames array. If it is, move onto the next element in edges, if it isn't, append the value to the cityNames array.
The code below adds the edges[i].startCity to the cityNames array but it does not check for duplicates and I can't figure out why.
for (int i = 1; i < noEdges; i++) {
for (int j = 0; j < noCities; j++) {
if(strcmp(edges[i].startCity, cityNames[j].cityName) != 0) {
strcpy(cityNames[i].cityName, edges[i].startCity);
}
}
noCities += 1;
}
Thanks in advance
I will assume that:
edges is an array of structures of a known length noEdges, each structure containing a string (either a char pointer or a char array)
cityNames is an array of structures for which the size is at least the number of distinct name (it could be noEdges or the size of the edges array)
the cityNames structure contain a char array element for which the size is at least the longest name + 1 (+1 for the terminating null)
Then the following code could give the unique names:
noCity = 0;
for (int i = 0; i < noEdges; i++) {
int dup = 0; // expect edges[i].startCity not to be a duplicate
for (int j = 0; j < noCities; j++) {
if(strcmp(edges[i].startCity, cityNames[j].cityName) == 0) {
dup = 1; // got a duplicate
break; // no need to go further ...
}
}
if (dup == 0) { // not a duplicate: add it to cityNames
strcpy(cityNames[noCities].cityName, edges[i].startCity);
noCities += 1; // we now have one more city
}
}
}
A good idea to start with would be to ditch working with strings if you can (or at least manipulate strings when actually needed).
You could start off by assigning each city name a number, that way you have an array of ints which is quicker and easier to work with.
Scanning for duplicates becomes trivial as you would now only be comparing numbers.
When you need to display the actual text on screen or write the city names to file, you could use the indexes associated with the city names to retrieve the appropriate textual representation of the index. You could then replace the data type of your cityNames[] to ints. This makes each 'node' which the 'edges' connect a number instead of text.
char* actualCityNames[n]; //array holding all city names with duplicates, could be a file also
char* indexedCityNames[n];//array with indexed cities (in order of appearance in actualCityNames, i.e. not alphabetical order)
//indexedCityNames will most likely not use up N slots if duplicates occur
//this is why there is a second counter for the size of indexed cities
int indexedCount = 0;//number of unique city names
int duplicates = 0;
//loop for actualCityNames slots
for(int i=0; i<n; i++){
//loop for indexedCityNames
for(int j=0; j<indexedCount; j++){
//strcmp returns 0 if both strings are the same
if(strcmp(actualCityNames[i],indexedCityNames[j]) == 0){
//duplicate found, mark flag
duplicates = 1;
}
}
if(!duplicates){
strcpy(indexedCityNames[indexedCount],actualCityNames[I]);
indexedCount++;
}
duplicates = 0;
}
Your code snippet does not check for duplicates because in the inner loop the if statement appends startCity as soon as a first cityName is encountered that is not equal to the current startCity.
Moreover in this statement
strcpy(cityNames[i].cityName, edges[i].startCity);
^^^
there is used an incorrect index.
And the variable noCities shall be incremented only when a new startCity is appended.
Also the outer loop should start from the index equal to 0.
Rewrite the loops the following way
int noCities = 0;
for ( int i = 0; i < noEdges; i++ ) {
int j = 0;
while ( j < noCities && strcmp(edges[i].startCity, cityNames[j].cityName) != 0 ) {
++j;
}
if ( j == noCities ) strcpy(cityNames[noCities++].cityName, edges[i].startCity);
}

Transform an array to another array by shifting value to adjacent element

I am given 2 arrays, Input and Output Array. The goal is to transform the input array to output array by performing shifting of 1 value in a given step to its adjacent element. Eg: Input array is [0,0,8,0,0] and Output array is [2,0,4,0,2]. Here 1st step would be [0,1,7,0,0] and 2nd step would be [0,1,6,1,0] and so on.
What can be the algorithm to do this efficiently? I was thinking of performing BFS but then we have to do BFS from each element and this can be exponential. Can anyone suggest solution for this problem?
I think you can do this simply by scanning in each direction tracking the cumulative value (in that direction) in the current array and the desired output array and pushing values along ahead of you as necessary:
scan from the left looking for first cell where
cumulative value > cumulative value in desired output
while that holds move 1 from that cell to the next cell to the right
scan from the right looking for first cell where
cumulative value > cumulative value in desired output
while that holds move 1 from that cell to the next cell to the left
For your example the steps would be:
FWD:
[0,0,8,0,0]
[0,0,7,1,0]
[0,0,6,2,0]
[0,0,6,1,1]
[0,0,6,0,2]
REV:
[0,1,5,0,2]
[0,2,4,0,2]
[1,1,4,0,2]
[2,0,4,0,2]
i think BFS could actually work.
notice that n*O(n+m) = O(n^2+nm) and therefore not exponential.
also you could use: Floyd-Warshall algorithm and Johnson’s algorithm, with a weight of 1 for a "flat" graph, or even connect the vertices in a new way by their actual distance and potentially save some iterations.
hope it helped :)
void transform(int[] in, int[] out, int size)
{
int[] state = in.clone();
report(state);
while (true)
{
int minPressure = 0;
int indexOfMinPressure = 0;
int maxPressure = 0;
int indexOfMaxPressure = 0;
int pressureSum = 0;
for (int index = 0; index < size - 1; ++index)
{
int lhsDiff = state[index] - out[index];
int rhsDiff = state[index + 1] - out[index + 1];
int pressure = lhsDiff - rhsDiff;
if (pressure < minPressure)
{
minPressure = pressure;
indexOfMinPressure = index;
}
if (pressure > maxPressure)
{
maxPressure = pressure;
indexOfMaxPressure = index;
}
pressureSum += pressure;
}
if (minPressure == 0 && maxPressure == 0)
{
break;
}
boolean shiftLeft;
if (Math.abs(minPressure) > Math.abs(maxPressure))
{
shiftLeft = true;
}
else if (Math.abs(minPressure) < Math.abs(maxPressure))
{
shiftLeft = false;
}
else
{
shiftLeft = (pressureSum < 0);
}
if (shiftLeft)
{
++state[indexOfMinPressure];
--state[indexOfMinPressure + 1];
}
else
{
--state[indexOfMaxPressure];
++state[indexOfMaxPressure + 1];
}
report(state);
}
}
A simple greedy algorithm will work and do the job in minimum number of steps. The function returns the total numbers of steps required for the task.
int shift(std::vector<int>& a,std::vector<int>& b){
int n = a.size();
int sum1=0,sum2=0;
for (int i = 0; i < n; ++i){
sum1+=a[i];
sum2+=b[i];
}
if (sum1!=sum2)
{
return -1;
}
int operations=0;
int j=0;
for (int i = 0; i < n;)
{
if (a[i]<b[i])
{
while(j<n and a[j]==0){
j++;
}
if(a[j]<b[i]-a[i]){
operations+=(j-i)*a[j];
a[i]+=a[j];
a[j]=0;
}else{
operations+=(j-i)*(b[i]-a[i]);
a[j]-=(b[i]-a[i]);
a[i]=b[i];
}
}else if (a[i]>b[i])
{
a[i+1]+=(a[i]-b[i]);
operations+=(a[i]-b[i]);
a[i]=b[i];
}else{
i++;
}
}
return operations;
}
Here -1 is a special value meaning that given array cannot be converted to desired one.
Time Complexity: O(n).

(double) for-loop with variable indexing in C

I have a buffer with IDs which looks like this
InBuffer={ID1,ID2,ID3,...}
I need to iterate through, every time using the ID in a function that returns pointers to the Data assigned to this ID and the size of the Data. I then need to fill in another buffer with the result which is of the form
OutBuffer={ID1,SIZE1,DATA1.WORD1,...,DATA1.WORDSIZE1,
ID2,SIZE2,DATA2.WORD1,...,DATA2.WORDSIZE2,
...,
IDN,SIZEN,DATAN.WORD1,...,DATAN.WORDSIZEN
}
I am having problems with forming the whole for-loop for this and the indexing of it, mainly because each SIZE variable can be different. It should be simple but I can't seem to make it work.
Thanks in advance for any help.
// For example
// Iterate through the remaining of the Request Buffer (m=0,1 already set)
for (m = 2; m < InBuffer; m++)`
{
OutBuffer[m] = InBuffer[m];
returnPointersToDataAndSizeFunction(InBuffer[m], &SIZE, &DATA);
OutBuffer[m + 1] = SIZE; // e.g. SIZE = 2, therefore DATA has 2 fields
OutBuffer[m + 2] = DATA.1; // first field
OutBuffer[m + 3] = DATA.2; // second field
// and so on
}
The first thing I notice is that you're using m to index both buffers:
for (m = 2; m < InBuffer; m++)
{
OutBuffer[m]=InBuffer[m];
but then you're using offsets from m for the additional data in OutBuffer:
OutBuffer[m+1]=SIZE;
OutBuffer[m+2]=DATA;
So, what you do think is going to happen in the next iteration of the loop? Say you go through the loop the first time, so that m is 2. The next time, it's m++, i.e. 3, and you make this assignment again:
OutBuffer[m]=InBuffer[m];
But you already assigned something at m[3], and that's the SIZE value from the previous iteration. You also assigned DATA at m[4], and that's going to be overwritten by the SIZE value in this iteration. Eventually, you'll end up with OutBuffer containing exactly what's in InBuffer, plus the SIZE and DATA values for the very last ID.
You need to use a different variable to index OutBuffer, something like:
for (m = 2, n = m; m < InBuffer; m++) {
OutBuffer[n++] = InBuffer[m];
returnPointersToDataAndSizeFunction(InBuffer[m],&SIZE,&DATA);
OutBuffer[n++] = SIZE;
OutBuffer[n++] = DATA;
}
There are some other problems as well. For example, the condition in the for loop shouldn't compare m to InBuffer, but should instead compare m and the number of entries in InBuffer. But just straightening out your indexing should be a big step forward.
Update: I just noticed that the data for each ID is larger than just one field. You'll need another loop inside the first one, then, so that you end up with something like this:
for (m = 2, n = m; m < InBuffer; m++) {
OutBuffer[n++] = InBuffer[m];
returnPointersToDataAndSizeFunction(InBuffer[m],&SIZE,&DATA);
OutBuffer[n++] = SIZE;
for (i = 0; i < SIZE; i++) {
OutBuffer[n++] = DATA[i];
}
}
If DATA is a structure with fields rather than an array, then you may need a series of if statements to check whether each field should be included or not. You can't use the value of a variable like i as the name of a field, i.e. you can't say DATA.i where i is a variable. I don't think a C structure can have field names that are numbers -- identifiers generally have to start with a letter or underscore, so trying to do that won't make much sense anyway. If you have control over the type of DATA, you should make it an array instead of a structure. So your loop would look more like this:
for (m = 2, n = m; m < InBuffer; m++) {
OutBuffer[n++] = InBuffer[m];
returnPointersToDataAndSizeFunction(InBuffer[m],&SIZE,&DATA);
OutBuffer[n++] = SIZE;
i = 0;
if (i++ < SIZE) { OutBuffer[n++] = DATA.field1; }
if (i++ < SIZE) { OutBuffer[n++] = DATA.field2; }
// and so on for each field in DATA's type
}
As Caleb pointed out you should use one variable for each array.
If you're saying that DATA can contain more than one element then you should increase the variable for outBuffer by SIZE each iteration. Also use a loop to asign DATAs fields to OutBuffer
int n = XXX; // set n to the first element you need to assign an ID to
for (m = 2; m < ElementsInBuffer; m++)
{
OutBuffer[n] = InBuffer[m];
returnPointersToDataAndSizeFunction(InBuffer[m],&SIZE,&DATA);
OutBuffer[n + 1] = SIZE;
for (int i = 0; i < SIZE; i++)
{
OutBuffer[n + 2 + i] = DATA[i]; // works for array only see Calebs answer to see how it works for structs
}
n += SIZE + 1; // +1 to also skip the field for SIZE
}

Perform Selection Sort On 2D Char Array

I currently have a 2D char array size: [5][256].
The array can hold either numbers or letters.
I have been tasked with using the Selection Sort to sort the strings into ascending order.
My idea is to convert each row into ASCII and then sort the values in ascending order then convert back to chars.
Ive implemented a 2D Array Selection sort for another task, however, it doesnt work here as i coded it to work with 2 columns not 256 like here (not sure how to change it).
What i need help with is how do i use the ASCII value for each row and use it in a selection sort.
Been trying to figure this out for hours now, driving me mental.
Any help is appreciated.
Im not necessarily looking for someone to code everything for me, more of a kick in the right direction. Im new to C and not aware of every function C can do.
Here is my current code in full:
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
char arc5Strings[5][256];
int nCount, nCount2, nCount3, nCount4, nCount5, nCount6, nCount7;
int fMinVal[1][2] = {1,1};
int nMinValPosition;
int nMoves;
int nRow;
int fTemp[1][2] = {1,1};
int fTemp2[1][2] = {1,1};
//input the values
for(nCount=0; nCount < 5; nCount++)
{
printf("Please input string %d/5: ", nCount + 1);
fgets(arc5Strings[nCount], 256, stdin);
}
printf("\n\n");
//print entire array
for(nCount3 = 0; nCount3 < 5; nCount3++)
{
for(nCount4 = 0; arc5Strings[nCount3][nCount4] != '\0'; nCount4++)
{
printf("%d ", arc5Strings[nCount3][nCount4]);
//ASCII values outputted in a line instead of in array format when using %c
}
}
return 0;
}
Old 2D Array selection sort i devised - extracted from code:
//-----------------------------------
//set up the switch
for(nCount5 = 0; nCount5 < 5; nCount5++)
{
fMinVal[0][0] = arc5Strings[nCount5][0]; //min value is row 0 col 1
nMinValPosition = nCount5;
for(nCount6 = nCount5 + 1; nCount6 < 5; nCount6++)
{
if(arc5Strings[nCount6][1] < fMinVal[0][0])
{
fMinVal[0][0] = arc5Strings[nCount6][0];
nMinValPosition = nCount6;
}
/* Perform the switch - actually switch the values */
if(fMinVal[0][0] < arc5Strings[nCount5][0])
{
fTemp[0][1] = arc5Strings[nCount5][1];
fTemp2[0][0] = arc5Strings[nCount5][0];
arc5Strings[nCount5][1] = arc5Strings[nMinValPosition][1];
arc5Strings[nCount5][0] = arc5Strings[nMinValPosition][0];
arc5Strings[nMinValPosition][1] = fTemp[0][1];
arc5Strings[nMinValPosition][0] = fTemp2[0][0];
nMoves++;
}
}
}
//------------------------------
printf("\n\n");
printf("The sorted list, in ascending order, using selection sort, is:\n\n");
for(nCount3 = 0; nCount3 < 5; nCount3++)
{
for(nCount4 = 0; arc5Strings[nCount3][nCount4] != '\0'; nCount4++)
{
printf("%c", arc5Strings[nCount3][nCount4]);
}
}
printf("\n %d moves were made to sort this list\n", nMoves);
EDIT - RESULTS OF GEORGE'S ANSWER:
Input1 = 90
Input2 = 70
Input3 = abc
Input4 = 500
Input5 = 200
Sorted Array Results:
200
90
70
abc
500
You're on the right track. I would implement this as follows:
for(i=0;i<5;i++)
{
indexOfCurrentSmallest = i;
for(j=i;j<5;j++)
{
for(k=0;k<255;k++)
{
if(arc5Strings[j][k] < arc5Strings[indexOfCurrentSmallest][k])
{
//we found a new possible smallest
indexOfCurrentSmallest = j;
break;
}
else if(arc5Strings[j][k] > arc5Strings[indexOfCurrentSmallest][k])
{
//no point in searching further, the one we are looking at is already larger than the one we found.
break;
}
}
}
//here, we have found the actual smallest, let's do a swap
for(q=0;q<255;q++)
{
temp = arc5Strings[i][q];
arc5Strings[i][q] = arc5Strings[indexOfCurrentSmallest][q];
arc5Strings[indexOfCurrentSmallest][q] = temp;
}
}
I haven't tested this code, but it should be roughly what you're looking for. Basically, it compares ASCII values starting at the left, until it finds a difference, and stores the index for later swapping after comparing all 5 strings.
EDIT I've now tested the code above, and it works now.
First find each string length
int length[5];
for(i = 0, i < 5, i++){
length[i] = strlen(arc5Strings[i]);
}
Sort the lengths. Those with the same, compare the value of the first letter.
Thats it.
valter

given an array, for each element, find out the total number of elements lesser than it, which appear to the right of it

I had previously posted a question, Given an array, find out the next smaller element for each element
now, i was trying to know , if there is any way to find out "given an array, for each element, find out the total number of elements lesser than it, which appear to the right of it"
for example, the array [4 2 1 5 3] should yield [3 1 0 1 0]??
[EDIT]
I have worked out a solution, please have a look at it, and let me know if there is any mistake.
1 Make a balanced BST inserting elements traversing the array from right to left
2 The BST is made in such a way that each element holds the size of the tree rooted at that element
3 Now while you search for the right position to insert any element, take account of the total size of the subtree rooted at left sibling + 1(for parent) if you move right
Now since, the count is being calculated at the time of insertion of an element, and that we are moving from right to left, we get the exact count of elements lesser than the given element appearing after it.
It can be solved in O(n log n).
If in a BST you store the number of elements of the subtree rooted at that node when you search the node (reaching that from the root) you can count number of elements larger/smaller than that in the path:
int count_larger(node *T, int key, int current_larger){
if (*T == nil)
return -1;
if (T->key == key)
return current_larger + (T->right_child->size);
if (T->key > key)
return count_larger(T->left_child, key, current_larger + (T->right_child->size) + 1);
return count_larger(T->right_child, key, current_larger)
}
** for example if this is our tree and we're searching for key 3, count_larger will be called for:
-> (node 2, 3, 0)
--> (node 4, 3, 0)
---> (node 3, 3, 2)
and the final answer would be 2 as expected.
Suppose the Array is 6,-1,5,10,12,4,1,3,7,50
Steps
1.We start building a BST from right end of the array.Since we are concerned with all the elements to right for any element.
2.Suppose we have formed the partial solution tree upto the 10.
3.Now when inserting 5 we do a tree traversal and insert to the right of 4.
Notice that each time we traverse to the right of any node we increment by 1 and add the no. of elements in left subtree of that node.
eg:
for 50 it is 0
for 7 it is 0
for 12 it is 1 right traversel + leftsubtree size of 7 = 1+3 =4
for 10 same as above.
for 4 it is 1+1 =2
While building bst we can easily maintain the left subtree size for each node by simply maintaining a variable corresponding to it and incrementing it by 1 each time a node traverses to the left by it.
Hence the Solution Average case O(nlogn).
We can use other optimizations such as predetermining whether array is sorted in decreasing order
find groups of element in decreasing order treat them as single.
I think is it possible to do it in O(nlog(n))with a modified version of quicksort. Basically each time you add an element to less, you check if this element rank in the original array was superior to the rank of the current pivot. It may look like
oldrank -> original positions
count -> what you want
function quicksort('array')
if length('array') ≤ 1
return 'array' // an array of zero or one elements is already sorted
select and remove a pivot value 'pivot' from 'array'
create empty lists 'less' and 'greater'
for each 'x' in 'array'
if 'x' ≤ 'pivot'
append 'x' to 'less'
if oldrank(x) > = oldrank(pivot) increment count(pivot)
else
append 'x' to 'greater'
if oldrank(x) < oldrank(pivot) increment count(x) //This was missing
return concatenate(quicksort('less'), 'pivot', quicksort('greater')) // two recursive calls
EDIT:
Actually it can be done using any comparison based sorting algorithm . Every time you compare two elements such that the relative ordering between the two will change, you increment the counter of the bigger element.
Original pseudo-code in wikipedia.
You can also use binary Index tree
int tree[1000005];
void update(int idx,int val)
{
while(idx<=1000000)
{
tree[idx]+=val;
idx+=(idx & -idx);
}
}
int sum(int idx)
{
int sm=0;
while(idx>0)
{
sm+=tree[idx];
idx-=(idx & -idx);
}
return sm;
}
int main()
{
int a[]={4,2,1,5,3};
int s=0,sz=6;
int b[10];
b[sz-1]=0;
for(int i=sz-2;i>=0;i--)
{
if(a[i]!=0)
{
update(a[i],1);
b[i]=sum(a[i]-1)+s;
}
else s++;
}
for(int i=0;i<sz-1;i++)
{
cout<<b[i]<<" ";
}
return 0;
}
//some array called newarray
for(int x=0; x <=array.length;x++)
{
for(int y=x;y<array.length;y++)
{
if(array[y] < array[x])
{
newarray[x] = newarray[x]+1;
}
}
}
something like this,where array is your input array and newarray your output array
make sure to initialize everything correctly(0 for the newarrays values)
Another approach without using the tree.
Construct another sorted array . For example for input array {12, 1, 2, 3, 0, 11, 4} it will be {0, 1, 2, 3, 4, 11, 12}
Now compare position of each element from input array with sorted array.For example 12 in first array is at 0 index while sorted array it’s as 6
Once comparison is done, remove element from both array
Other than using BST, we can also solve this problem optimally by doing some modification in merge sort algorithm (in O(n*logn) time).
If you observe this problem more carefully, you can say that in the problem we need to count the number of inversions required for each element to make the array sorted in ascending order, right?
So this problem can be solved using Divide and Conquer paradigm. Here you need to maintain an auxiliary array for storing the count of inversions required (i.e. elements smaller than it on the right side of it).
Below is a python program:
def mergeList(arr, pos, res, start, mid, end):
temp = [0]*len(arr)
for i in range(start, end+1):
temp[i] = pos[i]
cur = start
leftcur = start
rightcur = mid + 1
while leftcur <= mid and rightcur <= end:
if arr[temp[leftcur]] <= arr[temp[rightcur]]:
pos[cur] = temp[leftcur]
res[pos[cur]] += rightcur - mid - 1
leftcur += 1
cur += 1
else:
pos[cur] = temp[rightcur]
cur += 1
rightcur += 1
while leftcur <= mid:
pos[cur] = temp[leftcur]
res[pos[cur]] += end - mid
cur += 1
leftcur += 1
while rightcur <= end:
pos[cur] = temp[rightcur]
cur += 1
rightcur += 1
def mergeSort(arr, pos, res, start, end):
if start < end:
mid = (start + end)/2
mergeSort(arr, pos, res, start, mid)
mergeSort(arr, pos, res, mid+1, end)
mergeList(arr, pos, res, start, mid, end)
def printResult(arr, res):
print
for i in range(0, len(arr)):
print arr[i], '->', res[i]
if __name__ == '__main__':
inp = input('enter elements separated by ,\n')
inp = list(inp)
res = [0]*len(inp)
pos = [ind for ind, v in enumerate(inp)]
mergeSort(inp, pos, res, 0, len(inp)-1)
printResult(inp, res)
Time : O(n*logn)
Space: O(n)
You can also use an array instead of a binary search tree.
def count_next_smaller_elements(xs):
# prepare list "ys" containing item's numeric order
ys = sorted((x,i) for i,x in enumerate(xs))
zs = [0] * len(ys)
for i in range(1, len(ys)):
zs[ys[i][1]] = zs[ys[i-1][1]]
if ys[i][0] != ys[i-1][0]: zs[ys[i][1]] += 1
# use list "ts" as binary search tree, every element keeps count of
# number of children with value less than the current element's value
ts = [0] * (zs[ys[-1][1]]+1)
us = [0] * len(xs)
for i in range(len(xs)-1,-1,-1):
x = zs[i]+1
while True:
us[i] += ts[x-1]
x -= (x & (-x))
if x <= 0: break
x = zs[i]+1
while True:
x += (x & (-x))
if x > len(ts): break
ts[x-1] += 1
return us
print count_next_smaller_elements([40, 20, 10, 50, 20, 40, 30])
# outputs: [4, 1, 0, 2, 0, 1, 0]
Instead of BST, you can use stl map.
Start inserting from right.
After inserting an element, find its iterator:
auto i = m.find(element);
Then subtract it from m.end(). That gives you the number of elements in map which are greater than current element.
map<int, bool> m;
for (int i = array.size() - 1; i >= 0; --i) {
m[array[i]] = true;
auto iter = m.find(array[i])
greaterThan[i] = m.end() - iter;
}
Hope it helped.
Modified Merge sort: (Already tested code)
Takes O(nlogn) time.
public class MergeSort {
static HashMap<Integer, Integer> valueToLowerCount = new HashMap<Integer, Integer>();
public static void main(String[] args) {
int [] arr = new int[] {50, 33, 37, 26, 58, 36, 59};
int [] lowerValuesOnRight = new int[] {4, 1, 2, 0, 1, 0, 0};
HashMap<Integer, Integer> expectedLowerCounts = new HashMap<Integer, Integer>();
idx = 0;
for (int x: arr) {
expectedLowerCounts.put(x, lowerValuesOnRight[idx++]);
}
for (int x : arr) valueToLowerCount.put(x, 0);
mergeSort(arr, 0, arr.length-1);
//Testing
Assert.assertEquals("Count lower values on right side", expectedLowerCounts, valueToLowerCount);
}
public static void mergeSort(int []arr, int l, int r) {
if (r <= l) return;
int mid = (l+r)/2;
mergeSort(arr, l, mid);
mergeSort(arr, mid+1, r);
mergeDecreasingOrder(arr, l, mid, r);
}
public static void mergeDecreasingOrder(int []arr, int l, int lr, int r) {
int []leftArr = Arrays.copyOfRange(arr, l, lr+1);
int []rightArr = Arrays.copyOfRange(arr, lr+1, r+1);
int indexArr = l;
int i = 0, j = 0;
while (i < leftArr.length && j < rightArr.length) {
if (leftArr[i] > rightArr[j]) {
valueToLowerCount.put(leftArr[i], valueToLowerCount.get(leftArr[i]) + rightArr.length - j);
arr[indexArr++] = leftArr[i++];
}else {
arr[indexArr++] = rightArr[j++];
}
}
while (i < leftArr.length) {
arr[indexArr++] = leftArr[i++];
}
while (j < rightArr.length) {
arr[indexArr++] = rightArr[j++];
}
}
}
To find the total number of values on right-side which are greater than an array element, simply change single line of code:
if (leftArr[i] > rightArr[j])
to
if (leftArr[i] < rightArr[j])

Resources