How does one find the rank of each element of an array, averaging in the case of ties, efficiently? For example:
float[] rank(T)(T[] input) {
// Implementation
}
auto foo = rank([3,6,4,2,2]); // foo == [3, 5, 4, 1.5, 1.5]
The only way I can think of doing it requires allocating 3 arrays:
- A duplicate of the input array because it has to be sorted and we don't own it.
- An array to keep track of the order in which the input array was sorted.
- An array of ranks to return.
Does anyone know how to do this in O(N log N) time and O(1) auxiliary space (meaning the only array we have to allocate is the one we're going to return), or at least get rid of one of the three arrays above?
You can allocate the array you are going to return (let's call it R), initialize it to 0..n-1 and then "sort" the incoming array (called I) but using the comparison I[R[k]] vs. I[R[j]] instead of the normal R[k] vs. R[j] and then swapping the values in the R array as needed (instead of the values in the I array as usual).
You can implement this indirect sorting using either quicksort or heapsort (or bubblesort but that will mess up your complexity).
You only need to allocate one array - and some stack space for the indices.