An interview question:
Make a program which takes input 'N'(unsigned long) and prints two columns, 1st column prints numbers from 1 to N (in hexadecimal format) and second column prints the number of 1s in the binary representation of the number in the left column. Condition is that this program should not count 1s (so no computations 'per number' to get 1s/ no division operators).
I tried to implement this by leveraging fact that No of 1s in 0x0 to 0xF can be re-used to generate 1s for any number. I am pasting code ( basic one without error checking.) Its giving correct results but I am not happy with space usage. How can I improve on this? ( Also I am not sure if its what interviewer was looking for).
void printRangeFasterWay(){
uint64_t num = ~0x0 ;
cout << " Enter upper number " ;
cin >> num ;
uint8_t arrayCount[] = { 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4} ;
// This array will store information needed to print
uint8_t * newCount = new uint8_t[num] ;
uint64_t mask = 0x0 ;
memcpy(newCount, &arrayCount[0], 0x10) ;
uint64_t lower = 0;
uint64_t upper = 0xF;
uint64_t count = 0 ;
uint32_t zcount= 0 ;
do{
upper = std::min(upper, num) ;
for(count = lower ; count <= upper ; count++){
newCount[count] = (uint32_t)( newCount[count & mask] + newCount[(count & ~mask)>>(4*zcount)]) ;
}
lower += count ;
upper |= (upper<<4) ;
mask = ((mask<<4) | 0xF ) ;
zcount++ ;
}while(count<=num) ;
for(uint64_t xcount=0 ; xcount <= num ; xcount++){
cout << std::hex << " num = " << xcount << std::dec << " number of 1s = " << (uint32_t)newCount[xcount] << endl;
}
}
Enter upper number 18
num = 0 number of 1s = 0
num = 1 number of 1s = 1
num = 2 number of 1s = 1
num = 3 number of 1s = 2
num = 4 number of 1s = 1
num = 5 number of 1s = 2
num = 6 number of 1s = 2
num = 7 number of 1s = 3
num = 8 number of 1s = 1
num = 9 number of 1s = 2
num = a number of 1s = 2
num = b number of 1s = 3
num = c number of 1s = 2
num = d number of 1s = 3
num = e number of 1s = 3
num = f number of 1s = 4
num = 10 number of 1s = 1
num = 11 number of 1s = 2
num = 12 number of 1s = 2
I have a slightly different approach which should solve your memory problem. Its based on the fact that the bitwise operation i & -i
gives you the smallest power of two in the number i
. For example, for i = 5
, i & -i = 1
, for i = 6
, i & -i = 2
. Now, for code:
void countBits(unsigned N) {
for (int i = 0;i < N; i ++)
{
int bits = 0;
for (int j = i; j > 0; j= j - (j&-j))
bits++;
cout <<"Num: "<<i <<" Bits:"<<bits<<endl;
}
}
I hope I understood your question correctly. Hope that helps
Edit: Ok, try this - this is dynamic programming without using every bit in every number:
void countBits(unsigned N) {
unsigned *arr = new unsigned[N + 1];
arr[0]=0;
for (int i = 1;i <=N; i ++)
{
arr[i] = arr[i - (i&-i)] + 1;
}
for(int i = 0; i <=N; i++)
cout<<"Num: "<<i<<" Bits:"<<arr[i]<<endl;
}
Hopefully, this works better
Several of the answers posted so far make use of bit shifting (just another word for division by 2) or bit masking. This stikes me as a bit of a cheat. Same goes for using the '1' bit count in a 4 bit pattern then matching by chunks of 4 bits.
How about a simple recursive solution using an imaginary binary tree of bits. each left branch contains a '0', each right branch contains a '1'. Then do a depth first traversal counting the number of 1 bits on the way down. Once the bottom of the tree is reached add one to the counter, print out the number of 1 bits found so far, back out one level and recurse again.
Stop the recursion when the counter reaches the desired number.
I am not a C/C++ programmer, but here is a REXX solution that should translate without much imagination. Note the magic number 32 is just the number of bits in an Unsigned long. Set it to anything
/* REXX */
SAY 'Stopping number:'
pull StopNum
Counter = 0
CALL CountOneBits 0, 0
return
CountOneBits: PROCEDURE EXPOSE Counter StopNum
ARG Depth, OneBits
If Depth = 32 then Return /* Number of bits in ULong */
if Counter = StopNum then return /* Counted as high as requested */
call BitCounter Depth + 1, OneBits /* Left branch is a 0 bit */
call BitCounter Depth + 1, OneBits + 1 /* Right branch is a 1 bit */
Return
BitCounter: PROCEDURE EXPOSE Counter StopNum
ARG Depth, OneBits
if Depth = 32 then do /* Bottom of binary bit tree */
say D2X(Counter) 'contains' OneBits 'one bits'
Counter = Counter + 1
end
call CountOneBits Depth, OneBits
return
Results:
Stopping number:
18
0 contains 0 one bits
1 contains 1 one bits
2 contains 1 one bits
3 contains 2 one bits
4 contains 1 one bits
5 contains 2 one bits
6 contains 2 one bits
7 contains 3 one bits
8 contains 1 one bits
9 contains 2 one bits
A contains 2 one bits
B contains 3 one bits
C contains 2 one bits
D contains 3 one bits
E contains 3 one bits
F contains 4 one bits
10 contains 1 one bits
11 contains 2 one bits
This answer is resonably efficient in time and space.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With