1680. Concatenation of Consecutive Binary Numbers
Problem Description
This problem asks us to construct a large binary number that represents the concatenation of the binary representations of all the integers from 1
to n
, and then return the decimal value of this large binary number modulo 10^9 + 7
.
Imagine writing down all the numbers from 1
to n
in decimal, then converting each of those to binary and stringing all the binary numbers together into one long binary sequence. This problem is essentially about finding the decimal value of that long sequence, but since the number could be very large, we take its modulus with 10^9 + 7
to keep the result within manageable bounds.
For instance, if n = 3
, the binary representations are 1
for 1
, 10
for 2
, and 11
for 3
. Concatenating these binaries we would get 11011
. The decimal equivalent of 11011
is 27
.
Intuition
The solution relies on understanding how binary numbers work and realizing that to append a binary number b
to another binary number a
, you can shift a
to the left by the number of bits in b
and then use bitwise OR to add b
into a
.
Here's our thought process to arrive at the solution:
- We want to add each binary number from
1
ton
to our concatenation. To do this, we iterate over this range. - Before adding a new number, we must make space for it by shifting the bits of the current concatenated binary number to the left. The number of shifts equals the number of bits in the next number to add.
- We can find out when the number of bits increases by checking if the number is a power of two because that's when an additional bit is required (
2
,4
,8
, etc.). A neat trick to check if a number is a power of two is to use the expression(i & (i - 1)) == 0
. - Once we know how much to shift, we shift the current answer to the left by that amount and use bitwise OR to append the new number.
- We want our final result to be within the bounds of
10^9 + 7
, so we take the modulus after each concatenation to prevent overflow. - Keep appending the numbers in the described fashion, taking the modulus as needed, until you reach
n
. - The final result after appending all numbers and taking the modulus is our answer.
Using this approach ensures that we get the result without actually constructing an impossibly large binary number, which would be impractical and inefficient.
Learn more about Math patterns.
Solution Approach
The implementation of the solution follows a bitwise manipulation approach. Here's a step-by-step walkthrough of the algorithm referring to the given Python code:
-
Define a
mod
variable representing the modulo value10**9 + 7
. This ensures all operations are bound within this range to avoid integer overflow. -
Initialize
ans
andshift
to0
.ans
will hold the final result, andshift
represents the number of positions we need to shiftans
to the left to make space for the next binary number. -
Loop through each integer
i
from1
ton
(inclusive), performing the following steps:-
Check if
i
is a power of two by verifying whether(i & (i - 1)) == 0
. This works because a power of two in binary representation has a single1
followed by zeroes, and subtracting1
from it flips all the bits up to that1
(e.g.,1000
becomes0111
). The bitwise AND ofi
andi - 1
will be zero ifi
is a power of two. -
If
i
is a power of two, increment theshift
variable by one to account for the additional bit in the binary representation ofi
. -
Concatenate
i
toans
by left-shiftingans
byshift
positions (using the<<
operator) and then performing bitwise OR withi
(using the|
operator). This concatenates the binary representation ofi
to the right ofans
. -
Apply modulus operation to
ans
after the concatenation to ensure the result never exceeds10**9 + 7
.
-
-
After the loop,
ans
holds the decimal value of the concatenated binary string modulo10**9 + 7
, and we returnans
.
The Python code uses no additional data structures, taking advantage of bitwise operations for efficient manipulation of the numbers. The iterative method keeps memory usage low, as we only work with integers and update our answer bit by bit. There's a direct correlation between each number and its binary representation, making this approach highly suitable for this problem.
Ready to land your dream job?
Unlock your dream job with a 2-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's use the example where n = 5
to illustrate the solution approach. Our goal is to calculate the decimal value of the binary number formed by concatenating the binary representations of the numbers from 1
to n
.
Here's how the algorithm would proceed, step by step:
-
Initialize constants and variables:
mod = 10**9 + 7
ans = 0
(to hold the final result)shift = 0
(to indicate the number of bit positionsans
must be shifted)
-
Start looping from
i = 1
toi = 5
:-
When
i = 1
:- Binary representation is
1
. shift
does not increase because1 & (1 - 1)
is not equal to0
.ans = (ans << shift) | i
becomes(0 << 0) | 1
which is1
.- Apply modulus:
ans = 1
.
- Binary representation is
-
When
i = 2
:- Binary representation is
10
. - Since
2 & (2 - 1)
equals0
,shift
increments by1
(nowshift = 1
). ans = (ans << shift) | i
becomes(1 << 1) | 2
which is4 | 2
or110
in binary, which is6
in decimal.- Apply modulus:
ans = 6
.
- Binary representation is
-
When
i = 3
:- Binary representation is
11
. shift
does not increase because3 & (3 - 1)
is not equal to0
.ans = (ans << shift) | i
becomes(6 << 1) | 3
which is12 | 3
or1111
in binary, which is15
in decimal.- Apply modulus:
ans = 15
.
- Binary representation is
-
When
i = 4
:- Binary representation is
100
. - Since
4 & (4 - 1)
equals0
,shift
increments by1
(nowshift = 2
). ans = (ans << shift) | i
becomes(15 << 2) | 4
which is60 | 4
or111100
in binary, which is60
in decimal.- Apply modulus:
ans = 60
.
- Binary representation is
-
When
i = 5
:- Binary representation is
101
. shift
does not increase because5 & (5 - 1)
is not equal to0
.ans = (ans << shift) | i
becomes(60 << 2) | 5
which is240 | 5
or11110101
in binary, which is245
in decimal.- Apply modulus:
ans = 245
.
- Binary representation is
-
-
After the loop, we have
ans = 245
, which is the decimal value of the concatenated binary number11110101
(formed by concatenating1
,10
,11
,100
, and101
). As the final result is smaller than10**9 + 7
, it is also the return value.
By following these steps, we've converted the sequence of binary numbers to their concatenated decimal equivalent using bitwise manipulation and kept the value below 10**9 + 7
as required.
Solution Implementation
1class Solution:
2 def concatenatedBinary(self, n: int) -> int:
3 # Define the modulus to prevent integer overflow
4 modulus = 10**9 + 7
5
6 # Initialize the result and the number of bits to shift
7 result = shift = 0
8
9 # Iterate through each number from 1 to n
10 for num in range(1, n + 1):
11 # Check if the number is a power of 2 (has only one '1' in binary)
12 # If so, increase the shift counter as the binary length increases by 1
13 if (num & (num - 1)) == 0:
14 shift += 1
15
16 # Left shift the result by the number of bits required, then OR it with
17 # the current number, and take modulo to maintain the result within limits
18 result = (result << shift | num) % modulus
19
20 # Return the concatenated binary number modulo 10^9 + 7
21 return result
22
1class Solution {
2 public int concatenatedBinary(int n) {
3 // Constant for the modulus value to ensure the result stays within integer bounds
4 final int MOD = 1_000_000_007;
5
6 // Initialize answer as a long to avoid integer overflow
7 long answer = 0;
8
9 // Initialize the number of bits required for binary shift
10 int shiftCount = 0;
11
12 // Iterate over each number from 1 to n
13 for (int i = 1; i <= n; ++i) {
14 // Check if the current number is a power of two by using bitwise AND
15 // A number is a power of two if it has a single 1-bit and all other bits are 0
16 if ((i & (i - 1)) == 0) {
17 // If the current number is a power of two, increment the shift count
18 ++shiftCount;
19 }
20
21 // Concatenate the current number in binary to the answer
22 // Shift the current answer to the left by shiftCount bits
23 // OR with the current number to append it
24 // And take the result modulo MOD to keep it within bounds
25 answer = ((answer << shiftCount) | i) % MOD;
26 }
27
28 // Cast the answer back to an integer before returning
29 return (int) answer;
30 }
31}
32
1class Solution {
2public:
3 // Function to concatenate the binary representation of numbers from 1 to n
4 int concatenatedBinary(int n) {
5 const int MOD = 1e9 + 7; // Define the modulo to prevent integer overflow
6 long result = 0; // Initialize the result variable to store the concatenated binary number
7 int bitShift = 0; // Initialize bit shift count to determine how many positions to shift
8
9 // Loop through all numbers from 1 to n and build the concatenated binary representation
10 for (int i = 1; i <= n; ++i) {
11 // Check if 'i' is a power of 2 by using bitwise AND on 'i' and 'i-1'
12 // If i is a power of 2, the number of bits needed increases by 1
13 if ((i & (i - 1)) == 0) {
14 ++bitShift;
15 }
16 // Left shift the current result by the current bitShift value to make space for the new number 'i'
17 // OR with 'i' to append 'i' in its binary form to the result
18 // Apply modulo operation to keep the result within the MOD range
19 result = ((result << bitShift) | i) % MOD;
20 }
21 return result; // Return the final result after processing all numbers from 1 to n
22 }
23};
24
1function concatenatedBinary(n: number): number {
2 // Define the modulo constant for the final answer to avoid integer overflow.
3 const MOD = BigInt(10 ** 9 + 7);
4
5 // Initialize 'answer' to store our running binary concatenation result.
6 let answer = 0n;
7
8 // Initialize 'shiftCount' to keep track of the number of binary digits to shift.
9 let shiftCount = 0n;
10
11 // Iterate from 1 to n in BigInt to handle binary operations.
12 for (let i = 1n; i <= BigInt(n); ++i) {
13 // Check if 'i' is a power of 2, if it is, increment 'shiftCount'.
14 // This is done by checking if 'i' is a power of 2 by using bitwise AND on (i & (i - 1n)).
15 // If 'i' is a power of 2, (i & (i - 1n)) will be 0.
16 if ((i & (i - 1n)) == 0n) {
17 ++shiftCount;
18 }
19
20 // Perform the concatenation in binary by shifting 'answer' to the left by 'shiftCount' bits,
21 // then OR with 'i' to append 'i' to the binary representation.
22 // Apply modulo operation to keep the number within the MOD limit.
23 answer = ((answer << shiftCount) | i) % MOD;
24 }
25
26 // Return the final answer as a number (the answer is currently a BigInt).
27 return Number(answer);
28}
29
Time and Space Complexity
Time Complexity
The main operation of the code involves a for loop that iterates n
times, where n
is the input integer. Inside the loop, the code checks whether an integer is a power of two, which is performed in O(1) by using bitwise AND operation i & (i - 1)
. Then, the solution shifts the ans
variable to the left by shift
positions and performs a bitwise OR with the current number i
, also in constant time. Finally, it takes the modulus of the result, again an O(1) operation. Therefore, overall, the time complexity of this loop is O(n).
Space Complexity
The space complexity is O(1) because the algorithm uses a fixed number of integer variables (mod
, ans
, shift
, and i
) that do not depend on the size of the input number n
.
Learn more about how to find time and space complexity quickly using problem constraints.
What's the relationship between a tree and a graph?
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
LeetCode 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 we
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 algomonster s3 us east 2 amazonaws com recursion jpg You first
Want a Structured Path to Master System Design Too? Don’t Miss This!