Facebook Pixel

3827. Count Monobit Integers

EasyBit ManipulationEnumeration
LeetCode ↗

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 just 0), or
  • Has a binary representation made up entirely of 1s, such as 1 (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.

Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

How We Pick the Algorithm

Why Math / Bit Manipulation?

This problem maps to Math / Bit Manipulation through a short path in the full flowchart.

Math orbittricks?yesPrime orGCD?noMath / BitManipulation

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 Flowchart

Intuition

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:

  1. The integer is 0, where the single bit is 0.
  2. 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:

  1. Initialize the answer to account for 0 and the first all-1 number. We set ans = x = 1 and i = 1. Here, x represents the current all-1 number we are checking (starting at 1, which is 1 in binary), and ans starts at 1 to pre-count the integer 0, which is always valid.

  2. Loop while the current all-1 number is within range. As long as x <= n, the value x is a valid Monobit integer, so we increment ans by 1.

  3. Generate the next all-1 number. To move from the current all-1 number to the next one, we add the next higher bit using x += 1 << i, then increment i by 1. For example:

    • Start with x = 1 (1), i = 1.
    • Add 1 << 1 = 2, giving x = 3 (11), then i = 2.
    • Add 1 << 2 = 4, giving x = 7 (111), then i = 3.
    • Add 1 << 3 = 8, giving x = 15 (1111), and so on.
  4. Stop and return the count. Once x exceeds n, the loop ends, and we return ans, 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 integer 0, which is always a valid Monobit number.
  • x = 1 — the current all-1 number we are checking (1 in 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.
  • 1 is the all-1 number 1, which is valid, so increment: ans = 1 + 1 = 2.
  • Generate the next all-1 number: x += 1 << 1x = 1 + 2 = 3 (11 in 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-1 number: x += 1 << 2x = 3 + 4 = 7 (111 in 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-1 number: x += 1 << 3x = 7 + 8 = 15 (1111 in 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, since 15 > 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
19
1class 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}
36
1class 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};
57
1/**
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}
25

Time and Space Complexity

  • Time Complexity: O(log n)

    The loop continues while x <= n. In each iteration, the variable x is incremented by 1 << i (i.e., 2^i), where i starts at 1 and increases by 1 per iteration. Therefore, after k iterations, the accumulated value of x is 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 when x > n, which happens when 2^(k+1) ≈ n, i.e., k ≈ log₂(n). Thus, the number of iterations is proportional to log n, giving a time complexity of O(log n).

  • Space Complexity: O(1)

    The algorithm only uses a constant number of variables (ans, x, i) regardless of the input size n. No additional data structures that scale with the input are allocated, so the space complexity is O(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 Roadmap
Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Get a Personalized Study Roadmap:

Which of the two traversal algorithms (BFS and DFS) can be used to find whether two nodes are connected?


Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More