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

后端 未结 16 1949
轻奢々
轻奢々 2020-12-04 09:54

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)

相关标签:
16条回答
  • 2020-12-04 10:30

    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.

    0 讨论(0)
  • 2020-12-04 10:30

    Let k be the number of bits needed for n.

    for 0,...,2^(k-1)-1 each bit is up exactly for half of the numbers, so we have (k-1)*2^(k-1)/2 = (k-1)*2^(k-2) bits up so far. We only need to check what's up with the numbers that are bigger then 2^(k-1)-1
    We also have for those n-2^(k-1)-1 bits "up" for the MSB.

    So we can derive to the recursive function:

    f(n) = (k-1)*2^(k-2) + n-(2^(k-1)-1) + f(n-(2^(k-1)))
               ^               ^            ^
             first            MSBs        recursive call for 
           2^(k-1)-1                      n-2^(k-1) highest numbers
            numbers
    

    Where base is f(0) = 0 and f(2^k) = k*2^(k-1) + 1 [as we seen before, we know exactly how much bits are up for 2^(k-1)-1, and we just need to add 1 - for the MSB of 2^k]

    Since the value sent to f is reduced by by at least half at every iteration, we get total of O(logn)

    0 讨论(0)
  • 2020-12-04 10:33

    Here is my solution to this. Time complexity : O (Log n)

    public int countSetBits(int n){
        int count=0;
        while(n>0){
            int i= (int)(Math.log10(n)/Math.log10(2));
            count+= Math.pow(2, i-1)*i;
            count+= n-Math.pow(2, i)+1;
            n-= Math.pow(2, i);
        }
        return count;
    }
    
    0 讨论(0)
  • 2020-12-04 10:38

    Not sure if its late to reply, but here are my findings.

    Tried solving the problem with following approach, for number N every bitno ( from LSB to MSB, say LSB starts with bitno 1 and incrementing with next bit value) number of bits set can be calculated as , (N/(2 topower bitno) * (2 topower bitno-1) + { (N%(2 topower bitno)) - [(2 topower bitno-1) - 1] }

    Have written recursive function for it C/C++ please check. I am not sure but I think its complexity is log(N). Pass function 2 parameters, the number (no) for which we want bits to be calculated and second start count from LSB , value 1.

    int recursiveBitsCal(int no, int bitno){
    int res = int(no/pow(2,bitno))*int(pow(2,bitno-1));
    int rem1 = int(pow(2,bitno-1)) -1;
    int rem = no % int(pow(2,bitno));
    if (rem1 < rem) res += rem -rem1;
    if ( res <= 0 )
        return 0;
    else
        return res + recursiveBitsCal(no, bitno+1);
    }
    
    0 讨论(0)
提交回复
热议问题