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.
The way to solve these sorts of problems is to write out the first few values, and look for a pattern
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
0in the MSB (most significant bit), while the last 8 have a1. Thus, for example to calculateF(12), we can just takeF(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!Thus, for
8 <= n <= 15,F(n) = F(7) + F(n-8) + (n-7). Similarly, we could note that for4 <= n <= 7,F(n) = F(3) + F(n-4) + (n-3); and for2 <= n <= 3,F(n) = F(1) + F(n-2) + (n-1). In general, if we seta = 2^(floor(log(n))), thenF(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. Ifa = 2^x, then note in the table above that fora-1, the first bit is set exactlya/2times, the second bit is set exactlya/2times, 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 usWhere
x = floor(log(n)). Each iteration of calculatingFwill essentially remove the MSB; thus, this is anO(log(n))algorithm.