Write an algorithm to find F(n)
the number of bits set to 1, in all numbers from 1 to n for any given value of n.
Complexity should be O(log n)
For example:
1: 001 2: 010 3: 011 4: 100 5: 101 6: 110
So
F(1) = 1, F(2) = F(1) + 1 = 2, F(3) = F(2) + 2 = 4, F(4) = F(3) + 1 = 5, etc.
I can only design an O(n)
algorithm.
An alternate method to solve the problem is by using the shift operation to shift the number to right until it becomes 0. At the end the number of shifts done to reach 0 is the position of the set bit.
The way to solve these sorts of problems is to write out the first few values, and look for a pattern
Number binary # bits set F(n) 1 0001 1 1 2 0010 1 2 3 0011 2 4 4 0100 1 5 5 0101 2 7 6 0110 2 9 7 0111 3 12 8 1000 1 13 9 1001 2 15 10 1010 2 17 11 1011 3 20 12 1100 2 22 13 1101 3 25 14 1110 3 28 15 1111 4 32
It takes a bit of staring at, but with some thought you notice that the binary-representations of the first 8 and the last 8 numbers are exactly the same, except the first 8 have a 0
in the MSB (most significant bit), while the last 8 have a 1
. Thus, for example to calculate F(12)
, we can just take F(7)
and add to it the number of set bits in 8, 9, 10, 11 and 12. But that's the same as the number of set-bits in 0, 1, 2, 3, and 4 (ie. F(4)
), plus one more for each number!
# binary 0 0 000 1 0 001 2 0 010 3 0 011 4 0 100 5 0 101 6 0 110 7 0 111 8 1 000 <--Notice that rightmost-bits repeat themselves 9 1 001 except now we have an extra '1' in every number! 10 1 010 11 1 011 12 1 100
Thus, for 8 <= n <= 15
, F(n) = F(7) + F(n-8) + (n-7)
. Similarly, we could note that for 4 <= n <= 7
, F(n) = F(3) + F(n-4) + (n-3)
; and for 2 <= n <= 3
, F(n) = F(1) + F(n-2) + (n-1)
. In general, if we set a = 2^(floor(log(n)))
, then F(n) = F(a-1) + F(n-a) + (n-a+1)
This doesn't quite give us an O(log n)
algorithm; however, doing so is easy. If a = 2^x
, then note in the table above that for a-1
, the first bit is set exactly a/2
times, the second bit is set exactly a/2
times, the third bit... all the way to the x'th bit. Thus, F(a-1) = x*a/2 = x*2^(x-1)
. In the above equation, this gives us
F(n) = x*2x-1 + F(n-2x) + (n-2x+1)
Where x = floor(log(n))
. Each iteration of calculating F
will essentially remove the MSB; thus, this is an O(log(n))
algorithm.
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