I found this question here, but this is not the answer i am looking for. Hence, posting again.
A function of the form:
F( N ) = rank
means that Given a number N
in decimal representation, its rank is given as:
Starting from 0 to N, how many numbers are there with same number of set bits in its
binary representation.
I will go through an example to make it more clear.
N = 6 ( 0110 )
Its rank is 3.
1. 3 ( 0011 )
2. 5 ( 0101 )
3. 6 ( 0110 )
Now, given a number, find its rank.
The obvious approach is to start from 0 and check for number of set bits for each number till N-1
.
The question is:
Is there any logN solution?
Yes, there is a log n
solution.
Let n
have k
bits set, the most significant bit being in position p
(starting to count positions from 0, so 2^p <= n < 2^(p+1)
). Then there are pCk
(binomial coefficient, also choose(p,k)
) ways to place k
bits in the positions 0, ..., p-1
, all these give numbers with exactly k
set bits that are smaller than n
. If k == 1
, that's it, otherwise there remain the numbers with k
set bits and the p
-th bit set that are smaller than n
to consider. Those can be counted by determining the rank of n - 2^p
.
Code (not optimal, does some unnecessary recomputation, and doesn't all that it could do to avoid overflow):
unsigned long long binom(unsigned n, unsigned k) {
if (k == 0 || n == k) return 1;
if (n < k) return 0;
if (k > (n >> 1)) k = n-k;
unsigned long long res = n, j;
// We're not doing all we can to avoid overflow, as this is a proof of concept,
// not production code.
for(j = 2; j <= k; ++j) {
res *= (n+1-j);
res /= j;
}
return res;
}
unsigned popcount(unsigned long long n) {
unsigned k = 0;
while(n) {
++k;
n &= (n-1);
}
return k;
}
unsigned long long rank(unsigned long long n) {
if (n == 0) return 1;
unsigned p = 0, k = popcount(n);
unsigned long long mask = 1,h = n >> 1;
while(h > 0) {
++p;
h >>= 1;
}
mask <<= p;
unsigned long long r = binom(p,k);
r += rank(n-mask);
return r;
}
Tested in a loop for 0 <= n < 10^8
to check for mistakes without any mismatch found.
Check output here.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With