1680. Concatenation of Consecutive Binary Numbers
Problem Description
Given an integer n
, you need to concatenate the binary representations of all numbers from 1
to n
in order, then convert the resulting binary string back to its decimal value. Return this decimal value modulo 10^9 + 7
.
For example, if n = 3
:
- Binary of
1
is"1"
- Binary of
2
is"10"
- Binary of
3
is"11"
- Concatenating them gives
"11011"
- Converting
"11011"
to decimal gives27
- Return
27 % (10^9 + 7) = 27
The solution uses bit manipulation to efficiently compute this value. Instead of actually creating the concatenated binary string, it builds the result by shifting the current answer left by the appropriate number of bits (equal to the bit length of the current number i
) and then using bitwise OR to append i
. This is mathematically equivalent to concatenating the binary representations but much more efficient.
The key insight is that concatenating binary number i
to the existing result is the same as:
- Shifting the existing result left by
bit_length(i)
positions - Adding (or OR-ing) the value
i
to fill those positions
The modulo operation is applied at each step to prevent integer overflow.
Intuition
When we concatenate binary strings, what we're really doing mathematically is shifting bits. Think about concatenating "10"
and "11"
- we get "1011"
. This is equivalent to taking the decimal value 2
(which is "10"
in binary), shifting it left by 2 positions (since "11"
has 2 bits), and then adding 3
(which is "11"
in decimal).
The key observation is that concatenating binary strings is the same as:
- Taking the current accumulated value
- Shifting it left by the number of bits in the next number
- Adding the next number to fill those new bit positions
For example, if we have accumulated "110"
(decimal 6
) and want to append "11"
(decimal 3
):
- We shift
6
left by 2 bits:6 << 2 = 24
(binary"11000"
) - We add
3
:24 + 3 = 27
(binary"11011"
)
This gives us the concatenated result without actually working with strings!
The beauty of this approach is that we can use the bit_length() method to determine how many positions to shift. For any number i
, i.bit_length()
tells us exactly how many bits we need to shift the accumulated result before adding i
.
Since we only care about the final decimal value modulo 10^9 + 7
, we can apply the modulo operation at each step to keep the numbers manageable and prevent overflow. The bitwise OR operation (|
) is used instead of addition since we're filling empty bit positions, though addition would work the same way here since the shifted bits and the new bits don't overlap.
Learn more about Math patterns.
Solution Approach
The implementation uses bit manipulation to efficiently build the concatenated binary value without creating actual binary strings.
Algorithm Steps:
-
Initialize
ans = 0
to store our accumulated result and setmod = 10^9 + 7
for the modulo operation. -
Iterate through each number
i
from1
ton
:- Calculate the number of bits in
i
usingi.bit_length()
- Shift the current
ans
left by that many bits:ans << i.bit_length()
- Use bitwise OR to append
i
to the shifted result:(ans << i.bit_length()) | i
- Apply modulo to keep the number manageable:
% mod
- Calculate the number of bits in
Key Pattern - Bit Shifting Optimization:
As mentioned in the reference approach, there's a pattern to observe: when we reach a power of 2, the number of bits increases by 1. For example:
- Numbers 1 has 1 bit
- Numbers 2-3 have 2 bits
- Numbers 4-7 have 3 bits
- Numbers 8-15 have 4 bits
This means we could optimize further by tracking when the bit length changes instead of calculating it each time. However, the given solution calculates bit_length()
for each i
, which is still efficient since bit_length()
is an O(1) operation.
Why This Works:
For each number i
, the operation (ans << i.bit_length() | i)
is mathematically equivalent to:
- Moving all existing bits in
ans
to the left byi.bit_length()
positions - Filling the newly created rightmost positions with the bits of
i
This perfectly simulates the concatenation of binary strings but operates directly on integers, making it much more efficient than string manipulation.
The modulo operation is applied at each step to prevent integer overflow while preserving the correctness of the final result modulo 10^9 + 7
.
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through the solution with n = 4
to see how the bit manipulation approach works:
Initial State:
ans = 0
(binary: empty)mod = 10^9 + 7
Iteration 1: i = 1
- Binary of 1 is
"1"
(1 bit) ans = (0 << 1) | 1 = 0 | 1 = 1
- Binary result so far:
"1"
ans = 1 % mod = 1
Iteration 2: i = 2
- Binary of 2 is
"10"
(2 bits) - Current
ans = 1
(binary:"1"
) - Shift
ans
left by 2:1 << 2 = 4
(binary:"100"
) - OR with 2:
4 | 2 = 6
(binary:"110"
) - Binary result so far:
"110"
(concatenation of"1"
and"10"
) ans = 6 % mod = 6
Iteration 3: i = 3
- Binary of 3 is
"11"
(2 bits) - Current
ans = 6
(binary:"110"
) - Shift
ans
left by 2:6 << 2 = 24
(binary:"11000"
) - OR with 3:
24 | 3 = 27
(binary:"11011"
) - Binary result so far:
"11011"
(concatenation of"110"
and"11"
) ans = 27 % mod = 27
Iteration 4: i = 4
- Binary of 4 is
"100"
(3 bits) - Current
ans = 27
(binary:"11011"
) - Shift
ans
left by 3:27 << 3 = 216
(binary:"11011000"
) - OR with 4:
216 | 4 = 220
(binary:"11011100"
) - Binary result so far:
"11011100"
(concatenation of all:"1"
+"10"
+"11"
+"100"
) ans = 220 % mod = 220
Final Result: 220
The concatenated binary string is "11011100"
which equals 220 in decimal. This demonstrates how shifting and OR-ing builds the same result as string concatenation but operates directly on integers.
Solution Implementation
1class Solution:
2 def concatenatedBinary(self, n: int) -> int:
3 """
4 Calculate the decimal value of the binary concatenation of integers from 1 to n.
5
6 For example, if n = 3:
7 - Binary of 1 is "1"
8 - Binary of 2 is "10"
9 - Binary of 3 is "11"
10 - Concatenated: "11011" which equals 27 in decimal
11
12 Args:
13 n: The upper limit of integers to concatenate (1 to n)
14
15 Returns:
16 The decimal value of concatenated binary representation modulo 10^9 + 7
17 """
18 # Define modulo constant to prevent integer overflow
19 MOD = 10**9 + 7
20
21 # Initialize result accumulator
22 result = 0
23
24 # Iterate through each number from 1 to n
25 for current_num in range(1, n + 1):
26 # Get the number of bits required to represent current_num
27 num_bits = current_num.bit_length()
28
29 # Left shift result by num_bits positions to make room for current_num
30 # Then use bitwise OR to append current_num's binary representation
31 # Apply modulo to keep the number within bounds
32 result = ((result << num_bits) | current_num) % MOD
33
34 return result
35
1class Solution {
2 public int concatenatedBinary(int n) {
3 // Define modulo constant for preventing integer overflow
4 final int MOD = 1000000007;
5
6 // Initialize result variable to store the concatenated binary value
7 long result = 0;
8
9 // Iterate through each number from 1 to n
10 for (int currentNumber = 1; currentNumber <= n; currentNumber++) {
11 // Calculate the number of bits needed to represent currentNumber
12 // This is done by: 32 - (number of leading zeros in 32-bit representation)
13 int bitsRequired = 32 - Integer.numberOfLeadingZeros(currentNumber);
14
15 // Shift existing result left by bitsRequired positions to make room
16 // Then perform bitwise OR with currentNumber to append it
17 // Apply modulo to keep the result within bounds
18 result = ((result << bitsRequired) | currentNumber) % MOD;
19 }
20
21 // Cast and return the final result as an integer
22 return (int) result;
23 }
24}
25
1class Solution {
2public:
3 int concatenatedBinary(int n) {
4 // Define modulo constant for preventing integer overflow
5 const int MOD = 1000000007;
6
7 // Initialize result variable to store the concatenated binary value
8 long result = 0;
9
10 // Iterate through all numbers from 1 to n
11 for (int i = 1; i <= n; ++i) {
12 // Calculate the number of bits in current number i
13 // __builtin_clz(i) returns the number of leading zeros in 32-bit representation
14 // So (32 - __builtin_clz(i)) gives us the actual bit length of i
15 int bitLength = 32 - __builtin_clz(i);
16
17 // Left shift the current result by bitLength positions to make room for i
18 // Then use bitwise OR to append i to the result
19 // Apply modulo to keep the result within bounds
20 result = ((result << bitLength) | i) % MOD;
21 }
22
23 // Return the final concatenated binary value as an integer
24 return static_cast<int>(result);
25 }
26};
27
1/**
2 * Computes the decimal value of the binary concatenation of integers from 1 to n
3 * @param n - The upper bound of the range [1, n]
4 * @returns The decimal value modulo 10^9 + 7
5 */
6function concatenatedBinary(n: number): number {
7 // Define modulo constant as 10^9 + 7 for large number handling
8 const MODULO = BigInt(10 ** 9 + 7);
9
10 // Initialize result accumulator
11 let result = 0n;
12
13 // Number of bits needed to represent current number
14 let bitShift = 0n;
15
16 // Iterate through each number from 1 to n
17 for (let currentNumber = 1n; currentNumber <= n; ++currentNumber) {
18 // Check if current number is a power of 2
19 // When i is a power of 2, (i & (i - 1)) equals 0
20 // This means we need one more bit to represent numbers from this point
21 if ((currentNumber & (currentNumber - 1n)) === 0n) {
22 ++bitShift;
23 }
24
25 // Shift result left by the number of bits needed for current number
26 // Then OR with current number to append its binary representation
27 // Apply modulo to keep the number manageable
28 result = ((result << bitShift) | currentNumber) % MODULO;
29 }
30
31 // Convert BigInt result back to regular number
32 return Number(result);
33}
34
Time and Space Complexity
The time complexity is O(n)
, where n
is the given integer. The algorithm iterates through numbers from 1 to n exactly once in the for loop. Within each iteration, the operations performed are:
i.bit_length()
: This operation takesO(log i)
time, but since we're looking at the overall complexity andlog i ≤ log n
, and summing upO(log 1) + O(log 2) + ... + O(log n) = O(n log n)
would be an overestimate. However, the bit_length operation in Python is typically implemented to run inO(1)
time as it just reads the bit representation length.- Left shift operation
ans << i.bit_length()
:O(1)
- Bitwise OR operation
|
:O(1)
- Modulo operation
%
:O(1)
Therefore, each iteration performs constant time operations, resulting in an overall time complexity of O(n)
.
The space complexity is O(1)
. The algorithm only uses a fixed amount of extra space:
- Variable
mod
: stores a constant value - Variable
ans
: stores the accumulated result (single integer) - Variable
i
: loop counter
No additional data structures that grow with input size are used, so the space complexity remains constant regardless of the value of n
.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Forgetting to Apply Modulo at Each Step
Pitfall: A common mistake is applying the modulo operation only at the end instead of during each iteration:
# WRONG - This can cause integer overflow for large n
def concatenatedBinary(self, n: int) -> int:
result = 0
for i in range(1, n + 1):
result = (result << i.bit_length()) | i
return result % (10**9 + 7) # Modulo only at the end
Why it's problematic: For large values of n
, the intermediate result can grow exponentially and exceed integer limits, causing overflow or memory issues even in Python (which has arbitrary precision integers but still has practical memory limits).
Solution: Apply modulo at each iteration to keep the number bounded:
# CORRECT - Apply modulo at each step
def concatenatedBinary(self, n: int) -> int:
MOD = 10**9 + 7
result = 0
for i in range(1, n + 1):
result = ((result << i.bit_length()) | i) % MOD
return result
2. Using String Concatenation Instead of Bit Manipulation
Pitfall: Attempting to solve this problem by actually concatenating binary strings:
# INEFFICIENT - String manipulation approach
def concatenatedBinary(self, n: int) -> int:
binary_str = ""
for i in range(1, n + 1):
binary_str += bin(i)[2:] # Remove '0b' prefix
return int(binary_str, 2) % (10**9 + 7)
Why it's problematic:
- String concatenation has O(n²) time complexity due to string immutability
- Converting a very long binary string to integer is computationally expensive
- Memory usage grows linearly with the length of the concatenated string
Solution: Use the bit manipulation approach as shown in the original solution, which operates directly on integers and has O(n) time complexity with O(1) space.
3. Incorrect Bit Shifting Order
Pitfall: Confusing the order of operations or using addition instead of OR:
# WRONG - Using addition instead of OR result = ((result << i.bit_length()) + i) % MOD # WRONG - Shifting i instead of result result = ((i << result.bit_length()) | result) % MOD
Why it's problematic:
- Addition can cause incorrect results when there's bit overlap
- Shifting the wrong value completely breaks the concatenation logic
Solution: Always shift the accumulated result left, then OR with the current number:
# CORRECT result = ((result << i.bit_length()) | i) % MOD
Which data structure is used to implement recursion?
Recommended Readings
Math for Technical Interviews How much math do I need to know for technical interviews The short answer is about high school level math Computer science is often associated with math and some universities even place their computer science department under the math faculty However the reality is that you
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 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
Want a Structured Path to Master System Design Too? Don’t Miss This!