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)
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
.
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
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)
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:
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
)1st
bit position = (n/4 *2) + 1
(since 1st
bit is a set, else 0
)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)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
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;
}
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)