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

后端 未结 16 1948
轻奢々
轻奢々 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:16

    If n= 2^k-1, then F(n)=k*(n+1)/2

    For a general n, let m be the largest number such that m = 2^k-1 and m<=n. F(n) = F(m) + F(n-m-1) + (n-m).

    Corner condition: F(0)=0 and F(-1)=0.

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

    This question can be solved using DP with Bitmasking.

    The basic intuition behind bottom-up approach is that we are going to directly access number of set bits in the number having value current_number/2 and we are also going to check whether last bit is set in this current_number or not by just doing and operation with 1.

    current_number/2 or current_number>>1 basically removes the last bit of this current_number so to include that bit in our count we have to manually check the last bit of this number using & operation.

    This would be expression for computing number of set bits in a number i dp[i]=dp[i>>1]+(i&1)

    If you still get stuck while solving this question then you can refer to the following video for a better explanation:-

    Video Link: https://youtu.be/fCvfud4p6No

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

    A quick search for the values of the sequence F lead to this integer sequence http://oeis.org/A000788

    There I spotted a formula: a(0) = 0, a(2n) = a(n)+a(n-1)+n, a(2n+1) = 2a(n)+n+1 (a is the same as F since I just copy the formula from oeis)

    which could be used to compute a(n) in log(n).

    Here's my sample C++ code:

    memset(cache, -1, sizeof(cache))
    cache[0] = 0
    
    int f(int n)
        if cache[n] != -1 return cache[n];
        cache[n] = n % 2 ? (2 * f(n / 2) + n / 2 + 1) : (f(n / 2) + f(n / 2 - 1) + n / 2)
    
    0 讨论(0)
  • 2020-12-04 10:18

    consider the below:

    0000
    0001
    0010
    0011
    0100
    0101
    0110
    0111
    1000
    1001
    1010
    1011
    1100
    1101
    1110
    1111
    

    If you want to find total number of set bits from 1 to say 14 (1110) Few Observations:

    1. 0th bit (LSB) 1 bit appears once every two bit (see vertically) so number of set bits = n/2 +(1 if n's 0th bit is 1 else 0)
    2. 1st bit : 2 consecutive 1s appear every four bits (see 1st bit vertically along all numbers) number of set bits in 1st bit position = (n/4 *2) + 1 (since 1st bit is a set, else 0)
    3. 2nd bit: 4 consecutive 1s appear every 8 bits ( this one is a bit tricky) number of set bits in 2nd position = (n/8*4 )+ 1( since 2nd bit is set, else 0) + ((n%8)%(8/2)) The last term is to include the number of 1s that were outside first (n/8) group of bits (14/8 =1 considers only 1 group ie. 4 set bits in 8 bits. we need to include 1s found in last 14-8 = 6 bits)
    4. 3rd bit: 8 consecutive 1s appear every 16 bits (similar to above) number of set bits in 3rd position = (n/16*8)+1(since 3rd bit is set, else 0)+ ((n%16)%(16/2))

    so we do O(1) calculation for each bit of a number n. a number contains log2(n) bits. so when we iterate the above for all positions of n and add all the set bits at each step, we get the answer in O(logn) steps

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

    I know this post came in late to the party, please find logn solution below:

    static int countSetBitWithinRange(int n)
    {
        int x = n + 1, index = 0, count = 0;
        int numberOfOnesInAGroup = (int)Math.pow(2, index);
        while(x >= numberOfOnesInAGroup)
        {
            int countOfZeroOnePairs = (x / numberOfOnesInAGroup);
            int numberOfPairsOfZerosAndOnes = countOfZeroOnePairs / 2;
            int numberOfSetBits = numberOfPairsOfZerosAndOnes * numberOfOnesInAGroup;
            //If countOfZeroOnePairs is even then the pairs are complete else there will be ones that do not have a corresponding zeros pair
            int remainder = (countOfZeroOnePairs % 2 == 1) ? (x % numberOfOnesInAGroup) : 0;
            count = count + numberOfSetBits + remainder;
            numberOfOnesInAGroup = 1 << ++index;
        }
        return count;
    }
    
    0 讨论(0)
  • 2020-12-04 10:20
    for i in range(int(input())):
        n=int(input())
        c=0
        m=13
    
        if n==0:
            print(c)
        while n%8!=0 or n!=0:
            t=bin(n)[2:]
            c+=t.count('1')
            n=n-1
        if n!=0:
            j=n//8
            if j==1:
                c+=m
            else:
                c+=m+((j-1)*7)
        print(c)        
    
    0 讨论(0)
提交回复
热议问题