Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Finding the total number of set-bits from 1 to n

Tags:

algorithm

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.

like image 892
Fihop Avatar asked Mar 21 '12 20:03

Fihop


People also ask

How do you determine a set bit position?

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.


1 Answers

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.

like image 118
BlueRaja - Danny Pflughoeft Avatar answered Oct 05 '22 06:10

BlueRaja - Danny Pflughoeft