Approach #1 Brute Force [Time Limit Exceeded]
The brute force approach is simple. We can traverse through all the numbers from to . For every current number chosen, we can check all the consecutive positions in this number to check if the number contains two consecutive ones or not. If not, we increment the of the resultant numbers with no consecutive ones.
To check if a exists at the position (counting from the LSB side), in the current number , we can proceed as follows. We can shift a binary times towards the left to get a number which has a only at the position. Now, logical ANDing of and will result in a logical output only if contains at the position.
Time complexity : . We test the 32 consecutive positions of every number from to . Here, refers to given number.
Space complexity : . Constant space is used.
Approach #2 Better Brute Force [Time Limit Exceeded]
In the last approach, we generated every number and then checked if it contains consecutive ones at any position or not. Instead of this, we can generate only the required kind of numbers. e.g. If we genearte numbers in the order of the number of bits in the current number, if we get a binary number
110 on the way at the step of 3-bit number generation. Now, since this number already contains two consecutive ones, it is useless to generate number with more number of bits with the current bitstream as the suffix(e.g. numbers of the form
The current approach is based on the above idea. We can start with the LSB position, by placing a
0 and a
1 at the LSB. These two initial numbers correspond to the 1-bit numbers which don't contain any consecutive ones. Now, taking
0 as the initial suffix, if we want to generate two bit numbers with no two consecutive 1's, we can append a
1 and a
0 both in front of the initial
0 generating the numbers
00 as the two bit numbers ending with a
0 with no two consecutive 1's.
But, when we take
1 as the initial suffix, we can append a
0 to it to generate
01 which doesn't contain any consecutive ones. But, adding a
1 won't satisfy this criteria(
11 will be generated). Thus, while generating the current number, we need to keep a track of the point that whether a
1 was added as the last prefix or not. If yes, we can't append a new
1 and only
0 can be appended. If a
0 was appended as the last prefix, both
1 can be appended in the new bit-pattern without creating a violating number.
Thus, we can continue forward with the 3-bit number generation only with
10 as the new suffixes in the same manner.
To get a count of numbers lesser than , with no two consecutive 1's, based on the above discussion, we make use of a recursive function
find(i, sum, num, prev). This function returns the count of binary numbers with bits with no two consecutive 1's. Here, refers to the binary number generated till now(the prefix obtained as the input). refers to the given number. is a boolean variable that indicates whether the last prefix added was a
1 or a
If the last prefix was a
0, we can add both
0 as the new prefix. Thus, we need to make a function call
find(i + 1, sum, num, false) + find(i + 1, sum + (1 << i), num, true). Here, the first sub-part refers to a
0 being added at the position. Thus, we pass a
false as the prefix in this case. The second sub-part refers to a
1 being added at the position. Thus, we pass
true as the prefix in this case.
If the last prefix was a
1, we can add only a
0 as the new prefix. Thus, only one function call
find(i + 1, sum, num, false) is made in this case.
Further, we need to stop the number generation whenver the current input number() exceeds the given number .
Time complexity : . Only numbers are generated. Here, refers to the resultant count to be returned.
Space complexity : . The depth of recursion tree can go upto .
Approach #3 Using Bit Manipulation [Accepted]
Before we discuss the idea behind this approach, we consider another simple idea that will be used in the current approach.
Suppose, we need to find the count of binary numbers with bits such that these numbers don't contain consecutive 1's. In order to do so, we can look at the problem in a recursive fashion. Suppose gives the count of such binary numbers with bits. In order to determine the value of , which is the requirement, we can consider the cases shown below:
From the above figure, we can see that if we know the value of and , in order to generate the required binary numbers with bits, we can append a
0 to all the binary numbers contained in without creating an invalid number. These numbers give a factor of to be included in . But, we can't append a
1 to all these numbers, since it could lead to the presence of two consecutive ones in the newly generated numbers. Thus, for the currently generated numbers to end with a
1, we need to ensure that the second last position is always
0. Thus, we need to fix a
01 at the end of all the numbers contained in . This gives a factor of to be included in . Thus, in total, we get .
Now, let's look into the current approach. We'll try to understand the idea behind the approach by taking two simple examples. Firstly, we look at the case where the given number doesn't contain any consecutive 1's.Say, (7 bit number). Now, we'll see how we can find the numbers lesser than with no two consecutive 1's. We start off with the MSB of . If we fix a at the MSB position, and find out the count of 6 bit numbers(corresponding to the 6 LSBs) with no two consecutive 1's, these 6-bit numbers will lie in the range . For finding this count we can make use of which we'll have already calculated based on the discussion above.
But, even after doing this, all the numbers in the required range haven't been covered yet. Now, if we try to fix at the MSB, the numbers considered will lie in the range . As we can see, this covers the numbers in the range , but it covers the numbers in the range beyond limit as well. Thus, we can't fix at the MSB and consider all the 6-bit numbers at the LSBs.
For covering the pending range, we fix at the MSB, and move forward to proceed with the second digit(counting from MSB). Now, since we've already got a at this position, we can't substitute a here, since doing so will lead to generation of numbers exceeding . Thus, the only option left here is to substitute a at the second position. But, if we do so, and consider the 5-bit numbers(at the 5 LSBs) with no two consecutive 1's, these new numbers will fall in the range . But, again we can observe that considering these numbers leads to exceeding the required range. Thus, we can't consider all the 5-bit numbers for the required count by fixing at the second position.
Thus, now, we fix at the second position and proceed further. Again, we encounter a at the third position. Thus, as discussed above, we can fix a at this position and find out the count of 4-bit consecutive numbers with no two consecutive 1's(by varying only the 4 LSB bits). We can obtain this value from . Thus, now the numbers in the range have been covered up.
Again, as discussed above, now we fix a at the third position, and proceed with the fourth bit. It is a . So, we need to fix it as such as per the above discussion, and proceed with the fifth bit. It is a . So, we fix a here and consider all the numbers by varying the two LSBs for finding the required count of numbers in the range . Now, we proceed to the sixth bit, find a there. So, we fix at the sixth position and proceed to the seventh bit which is again . So, we fix a at the seventh position as well.
Now, we can see, that based on the above procedure, the numbers in the range , , have been considered and the counts for these ranges have been obtained as , and respectively. Now, only is pending to be considered in the required count. Since, it doesn't contain any consecutive 1's, we add a 1 to the total count obtained till now to consider this number. Thus, the result returned is .
Now, we look at the case, where contains some consecutive 1's. The idea will be the same as the last example, with the only exception taken when the two consecutive 1's are encountered. Let's say, (7 bit number). Now, as per the last discussion, we start with the MSB. We find a at this position. Thus, we initially fix a at this position to consider the numbers in the range , by varying the 6 LSB bits only. The count of the required numbers in this range is again given by .
Now, we fix a at the MSB and move on to the second bit. It is a , so we have no choice but to fix at this position and to proceed with the third bit. It is a , so we fix a here, considering the numbers in the range . This accounts for a factor of . Now, we fix a at the third positon, and proceed with the fourth bit. It is a (consecutive to the previous ). Now, initially we fix a at the fourth position, considering the numbers in the range . This adds a factor of to the required count.
Now, we can see that till now the numbers in the range , , have been considered. But, if we try to consider any number larger than , it leads to the presence of two consecutive 1's in the new number at the third and fourth position. Thus, all the valid numbers upto have been considered with this, giving a resultant count of .
Thus, summarizing the above discussion, we can say that we start scanning the given number from its MSB. For every 1 encountered at the bit position(counting from 0 from LSB), we add a factor of to the resultant count. For every 0 encountered, we don't add any factor. We also keep a track of the last bit checked. If we happen to find two consecutive 1's at any time, we add the factors for the positions of both the 1's and stop the traversal immediately. If we don't find any two consecutive 1's, we proceed till reaching the LSB and add an extra 1 to account for the given number as well, since the procedure discussed above considers numbers upto without including itself.
Time complexity : . One loop to fill array and one loop to check all bits of .
Space complexity : . array of size 32 is used.
Analysis written by: @vinod23