3827. Count Monobit Integers
Problem Description
You are given an integer n.
An integer is called Monobit if all the bits in its binary representation are the same. In other words, a Monobit integer either:
- Equals
0(its binary representation is just0), or - Has a binary representation made up entirely of
1s, such as1(1),3(11),7(111),15(1111), and so on.
Your task is to return the count of Monobit integers in the range [0, n] (inclusive).
For example, if n = 8, the Monobit integers in the range [0, 8] are 0, 1, 3, and 7. So the answer would be 4. The integer 8 (1000) is not Monobit because its bits are not all the same, and 15 (1111) is excluded since it is greater than n.
How We Pick the Algorithm
Why Math / Bit Manipulation?
This problem maps to Math / Bit Manipulation through a short path in the full flowchart.
Generating all-ones numbers (1, 3, 7, 15, ...) by repeated addition of powers of two and counting those within n is a bit manipulation enumeration.
Open in FlowchartIntuition
The key observation is that Monobit integers form a very limited and predictable set. Since all bits must be the same, there are only two possibilities for what the binary representation can look like:
- The integer is
0, where the single bit is0. - The integer's binary representation consists entirely of
1s.
The second group is especially easy to generate. Numbers whose binary form is all 1s follow a clear pattern: 1 (1), 3 (11), 7 (111), 15 (1111), and so on. Each of these values is exactly one less than a power of two, and we can build the next one from the current one by adding the next higher bit. For instance, starting from 1, we add 1 << 1 = 2 to get 3, then add 1 << 2 = 4 to get 7, then add 1 << 3 = 8 to get 15, and so forth.
Because these all-1 numbers grow very quickly (roughly doubling each time), only a small handful of them can possibly fall within the range [0, n]. This means we can simply start from 1 and keep generating the next all-1 number, counting each one as long as it stays within n.
Putting it together, we first account for 0, which is always a valid Monobit integer in the range. Then we walk through the all-1 numbers one by one, incrementing our count for each value that does not exceed n. Once a generated value goes beyond n, we stop, since every subsequent value will only be larger.
Solution Approach
We use a simulation strategy, directly generating each Monobit integer and counting how many lie within the range [0, n].
According to the analysis, a Monobit integer is either 0 or a number whose binary representation consists entirely of 1s. We handle these two cases together as follows:
-
Initialize the answer to account for
0and the first all-1number. We setans = x = 1andi = 1. Here,xrepresents the current all-1number we are checking (starting at1, which is1in binary), andansstarts at1to pre-count the integer0, which is always valid. -
Loop while the current all-
1number is within range. As long asx <= n, the valuexis a valid Monobit integer, so we incrementansby1. -
Generate the next all-
1number. To move from the current all-1number to the next one, we add the next higher bit usingx += 1 << i, then incrementiby1. For example:- Start with
x = 1(1),i = 1. - Add
1 << 1 = 2, givingx = 3(11), theni = 2. - Add
1 << 2 = 4, givingx = 7(111), theni = 3. - Add
1 << 3 = 8, givingx = 15(1111), and so on.
- Start with
-
Stop and return the count. Once
xexceedsn, the loop ends, and we returnans, which now holds the total count of Monobit integers in[0, n].
The code below implements this directly:
class Solution:
def countMonobit(self, n: int) -> int:
ans = x = 1
i = 1
while x <= n:
ans += 1
x += 1 << i
i += 1
return ans
Because each all-1 number roughly doubles in size each step, the loop runs about O(log n) times. The space complexity is O(1), since we only use a few integer variables regardless of the input size.
Example Walkthrough
Let's trace through the solution approach with a small example: n = 8.
We expect the answer to be 4, since the Monobit integers in [0, 8] are 0, 1, 3, and 7.
Initialization:
We start by setting up our variables:
ans = 1— this pre-counts the integer0, which is always a valid Monobit number.x = 1— the current all-1number we are checking (1in binary).i = 1— tracks which bit position we add next.
So before the loop begins, ans already accounts for 0.
Iteration 1:
- Check the condition: is
x (1) <= n (8)? Yes. 1is the all-1number1, which is valid, so increment:ans = 1 + 1 = 2.- Generate the next all-
1number:x += 1 << 1→x = 1 + 2 = 3(11in binary). - Increment bit position:
i = 2.
So far, we've counted 0 and 1.
Iteration 2:
- Check the condition: is
x (3) <= n (8)? Yes. 3(11) is valid, so increment:ans = 2 + 1 = 3.- Generate the next all-
1number:x += 1 << 2→x = 3 + 4 = 7(111in binary). - Increment bit position:
i = 3.
So far, we've counted 0, 1, and 3.
Iteration 3:
- Check the condition: is
x (7) <= n (8)? Yes. 7(111) is valid, so increment:ans = 3 + 1 = 4.- Generate the next all-
1number:x += 1 << 3→x = 7 + 8 = 15(1111in binary). - Increment bit position:
i = 4.
So far, we've counted 0, 1, 3, and 7.
Iteration 4:
- Check the condition: is
x (15) <= n (8)? No, since15 > 8. - The loop terminates.
Result:
We return ans = 4, which matches the expected count. The Monobit integers found were 0, 1, 3, and 7. The value 15 was correctly excluded because it exceeded n, and the loop stopped immediately once x grew beyond the range.
This walkthrough demonstrates how the loop runs only about O(log n) times (3 iterations here), since each all-1 number roughly doubles, quickly surpassing n.
Solution Implementation
1class Solution:
2 def countMonobit(self, n: int) -> int:
3 # count starts at 1 to account for the base case
4 count = 1
5 # current represents numbers of the form 2^k - 1 (binary: all ones),
6 # i.e. 1, 3, 7, 15, 31, ...
7 current = 1
8 # shift is the bit position used to add the next power of two
9 shift = 1
10
11 # iterate while the accumulated "all-ones" value does not exceed n
12 while current <= n:
13 count += 1
14 # add the next power of two: 2, 4, 8, ...
15 current += 1 << shift
16 shift += 1
17
18 return count
191class Solution {
2 public int countMonobit(int n) {
3 // ans counts how many "all-ones" binary numbers (1, 3, 7, 15, ...) fit within n,
4 // starting at 1 to account for the base case.
5 int ans = 1;
6
7 // threshold represents numbers of the form 2^k - 1: 1, 3, 7, 15, ...
8 // i drives the bit shift; each iteration adds the next power of two.
9 for (int i = 1, threshold = 1; threshold <= n; ++i) {
10 // Count this all-ones number since it does not exceed n.
11 ++ans;
12
13 // Advance threshold from (2^i - 1) to (2^(i+1) - 1) by adding 2^i.
14 threshold += (1 << i);
15 }
16
17 return ans;
18 }
19}
20```
21
22**A few notes on alternative perspectives:**
23
241. **Naming choice:** I renamed `x` to `threshold` since it represents the upper bound being tested. You could also name it `allOnes` to emphasize its binary pattern (`1, 11, 111, ...`).
25
262. **Potential overflow caution:** When `i` reaches 31, `1 << i` can overflow into negative values, and `threshold` could overflow too. For large `n`, a safer approach uses the bit length directly:
27
28```java
29class Solution {
30 public int countMonobit(int n) {
31 // The number of all-ones values (1, 3, 7, ...) that are <= n
32 // equals the bit length of n; add 1 to match the original base case.
33 return 32 - Integer.numberOfLeadingZeros(n) + 1;
34 }
35}
361class Solution {
2public:
3 int countMonobit(int n) {
4 // Count starts at 1 to account for the base case (value 1, i.e., 2^0)
5 int count = 1;
6
7 // 'value' represents numbers of the form (2^k - 1): 1, 3, 7, 15, ...
8 // which are binary numbers consisting entirely of consecutive 1-bits.
9 // 'bitIndex' tracks the next power of two to add into 'value'.
10 for (int bitIndex = 1, value = 1; value <= n; ++bitIndex) {
11 // Each qualifying value increments the count.
12 ++count;
13
14 // Add the next power of two (2^bitIndex) to extend the all-ones pattern.
15 value += (1 << bitIndex);
16 }
17
18 return count;
19 }
20};
21```
22
23**A few observations and alternative perspectives:**
24
251. **Potential overflow concern:** When `n` is large (close to `INT_MAX`), the expression `value += (1 << bitIndex)` can overflow a signed 32-bit `int`, causing undefined behavior. A safer variant uses `long long` for `value` and the shift:
26
27```cpp
28class Solution {
29public:
30 int countMonobit(int n) {
31 int count = 1;
32 // Use long long to avoid signed overflow when n is near INT_MAX.
33 for (int bitIndex = 1; (1LL << (bitIndex + 1)) - 1 <= n; ++bitIndex) {
34 ++count;
35 }
36 return count;
37 }
38};
39```
40
412. **Mathematical perspective:** Since the qualifying values are exactly `2^k - 1`, the answer equals the number of bits in `n` (i.e., the count of all-ones numbers not exceeding `n`). This can be computed directly:
42
43```cpp
44class Solution {
45public:
46 int countMonobit(int n) {
47 // The largest all-ones number <= n has the same bit-length as n.
48 // Equivalent to counting how many of 1, 3, 7, 15, ... are <= n.
49 int count = 0;
50 while (n > 0) {
51 ++count;
52 n >>= 1; // Drop one bit each iteration.
53 }
54 return count;
55 }
56};
571/**
2 * Counts a value based on consecutive "all-ones" binary numbers (1, 3, 7, 15, ...)
3 * that do not exceed the given limit n.
4 *
5 * @param n - The upper bound to compare against the accumulated value.
6 * @returns The computed count.
7 */
8function countMonobit(n: number): number {
9 // Start the answer at 1 to account for the base case.
10 let answer = 1;
11
12 // `index` tracks the current bit position (1, 2, 3, ...).
13 // `value` accumulates all-ones binary numbers: 1, 3, 7, 15, ...
14 for (let index = 1, value = 1; value <= n; ++index) {
15 // For every all-ones value within the limit, increment the answer.
16 ++answer;
17
18 // Add the next power of two (2^index) to extend `value`
19 // to the next all-ones binary number.
20 value += 1 << index;
21 }
22
23 return answer;
24}
25Time and Space Complexity
-
Time Complexity:
O(log n)The loop continues while
x <= n. In each iteration, the variablexis incremented by1 << i(i.e.,2^i), whereistarts at1and increases by1per iteration. Therefore, afterkiterations, the accumulated value ofxis approximately:x ≈ 1 + (2^1 + 2^2 + ... + 2^k) = 1 + (2^(k+1) - 2)This grows exponentially with the number of iterations
k. The loop terminates whenx > n, which happens when2^(k+1) ≈ n, i.e.,k ≈ log₂(n). Thus, the number of iterations is proportional tolog n, giving a time complexity ofO(log n). -
Space Complexity:
O(1)The algorithm only uses a constant number of variables (
ans,x,i) regardless of the input sizen. No additional data structures that scale with the input are allocated, so the space complexity isO(1).
Pattern Learn more about how to find time and space complexity quickly.
Common Pitfalls
Pitfall 1: Forgetting to Count 0 as a Monobit Integer
The most frequent mistake is initializing the count to 0 instead of 1. Since 0 is always a valid Monobit integer (its binary representation is just 0) and 0 is always within the range [0, n] for any non-negative n, it must be pre-counted.
Incorrect Code:
class Solution:
def countMonobit(self, n: int) -> int:
count = 0 # BUG: forgets to account for 0
current = 1
shift = 1
while current <= n:
count += 1
current += 1 << shift
shift += 1
return count
For n = 8, this incorrectly returns 3 (counting only 1, 3, 7) instead of 4.
Solution: Initialize count = 1 to pre-count 0, as done in the correct implementation. The loop then only handles the all-1s numbers (1, 3, 7, ...).
Pitfall 2: Off-by-One Error in the Loop Condition
Using current < n instead of current <= n causes the boundary case to be missed. When n itself is exactly an all-1s number (e.g., n = 7), a strict < comparison would fail to count n.
Incorrect Code:
while current < n: # BUG: should be <=
count += 1
current += 1 << shift
shift += 1
For n = 7, this returns 3 (0, 1, 3) instead of the correct 4 (0, 1, 3, 7), because current = 7 fails the 7 < 7 check.
Solution: Use current <= n so that an n that is itself a Monobit value gets counted.
Pitfall 3: Incrementing count After the Range Check Instead of Inside
A subtle structural error is incrementing the count and then breaking, or rearranging the order of operations so the final valid value gets double-counted or skipped. The increment must happen inside the loop, immediately after confirming current <= n.
Incorrect Code:
while current <= n:
current += 1 << shift
shift += 1
count += 1 # BUG: count is tied to the *next* value, not the current valid one
Here, when current is valid but the next value overshoots, the logic still works by coincidence in some cases, but the variable's meaning becomes inconsistent and error-prone if the structure is modified later.
Solution: Keep the increment directly after the loop condition is satisfied, ensuring each count += 1 corresponds to a confirmed in-range Monobit number:
while current <= n: count += 1 # current is confirmed valid here current += 1 << shift shift += 1
Pitfall 4: Misunderstanding the Definition (Treating All Powers of Two as Monobit)
A conceptual error is assuming numbers like 2 (10), 4 (100), or 8 (1000) are Monobit because they "look simple." Monobit requires all bits to be identical, so only all-1s patterns (and 0) qualify — not numbers with a single 1 followed by zeros.
Solution: Verify the generation logic produces only 1, 3, 7, 15, ... (each of the form 2^k - 1), confirming that intermediate powers of two are never counted.
Ready to land your dream job?
Unlock your dream job with a 5-minute quiz for a personalized study roadmap!
Get My RoadmapWhich of the two traversal algorithms (BFS and DFS) can be used to find whether two nodes are connected?
Recommended Readings
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion If you prefer videos here's a video that explains recursion in a fun and easy way Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask him
Runtime Overview When learning about algorithms and data structures you'll frequently encounter the term time complexity This concept is fundamental in computer science and offers insights into how long an algorithm takes to complete given a certain input size What is Time Complexity Time complexity describes how the time needed
Want a Structured Path to Master System Design Too? Don’t Miss This!