Skip to content

Commit 9ae922c

Browse files
committed
LeetCode 1680. Concatenation of Consecutive Binary Numbers
1 parent cb14ca4 commit 9ae922c

File tree

3 files changed

+226
-0
lines changed

3 files changed

+226
-0
lines changed

.github/workflows/markdown.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,4 @@ jobs:
2020
config-file: ".config/mlc_config.json"
2121
# folder-path: 'docs/markdown_files'
2222
check-modified-files-only: "yes"
23+
base-branch: "main"

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,7 @@ Solutions to LeetCode problems. The first column links to the problem in LeetCod
234234
| [1642. Furthest Building You Can Reach][lc1642] | 🟠 Medium | [![python](res/py.png)](leetcode/furthest-building-you-can-reach.py) |
235235
| [1647. Minimum Deletions to Make Character Frequencies Unique][lc1647] | 🟠 Medium | [![python](res/py.png)][lc1647py] |
236236
| [1658. Minimum Operations to Reduce X to Zero][lc1658] | 🟠 Medium | [![python](res/py.png)][lc1658py] |
237+
| [1680. Concatenation of Consecutive Binary Numbers][lc1680] | 🟠 Medium | [![python](res/py.png)][lc1680py] |
237238
| [1689. Partitioning Into Minimum Number Of Deci-Binary Numbers][lc1689] | 🟠 Medium | [![python](res/py.png)][lc1689py] |
238239
| [1695. Maximum Erasure Value][lc1695] | 🟠 Medium | [![python](res/py.png)][lc1695py] |
239240
| [1696. Jump Game VI][lc1696] | 🟠 Medium | [![python](res/py.png)][lc1696py] |
@@ -671,6 +672,8 @@ Solutions to LeetCode problems. The first column links to the problem in LeetCod
671672
[lc1647py]: leetcode/minimum-deletions-to-make-character-frequencies-unique.py
672673
[lc1658]: https://leetcode.com/problems/minimum-operations-to-reduce-x-to-zero/
673674
[lc1658py]: leetcode/minimum-operations-to-reduce-x-to-zero.py
675+
[lc1680]: https://leetcode.com/problems/concatenation-of-consecutive-binary-numbers/
676+
[lc1680py]: leetcode/concatenation-of-consecutive-binary-numbers.py
674677
[lc1689]: https://leetcode.com/problems/partitioning-into-minimum-number-of-deci-binary-numbers/
675678
[lc1689py]: leetcode/partitioning-into-minimum-number-of-deci-binary-numbers.py
676679
[lc1695]: https://leetcode.com/problems/maximum-erasure-value/
Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
# 1680. Concatenation of Consecutive Binary Numbers
2+
# 🟠 Medium
3+
#
4+
# https://leetcode.com/problems/concatenation-of-consecutive-binary-numbers/
5+
#
6+
# Tags: Math - Bit Manipulation - Simulation
7+
8+
import timeit
9+
from itertools import accumulate
10+
11+
# 1 call
12+
# » OneLine 0.00264 seconds
13+
# » ListComprehension 0.00313 seconds
14+
# » BitCountIntSum 0.00229 seconds
15+
# » MtrxMultiplication 0.00063 seconds
16+
# » GeomProgression 0.00025 seconds
17+
# » GemProg2 0.00013 seconds
18+
19+
# Use list comprehension and cast to string to generate the binary
20+
# representation of the values 1..n then convert to int and modulo it.
21+
#
22+
# Time complexity: O(n) - Where n is the number of binary digits of the
23+
# result string.
24+
# Space complexity: O(n) - We need to generate a string of size n binary
25+
# digits.
26+
#
27+
# Runtime: 2681 ms, faster than 51.97%
28+
# Memory Usage: 23.9 MB, less than 14.17%
29+
class OneLine:
30+
def concatenatedBinary(self, n: int) -> int:
31+
return int("".join([bin(x)[2:] for x in range(1, n + 1)]), 2) % (
32+
10**9 + 7
33+
)
34+
35+
36+
# Use list comprehension and cast to string to generate the binary
37+
# representation of the values 1..n then convert to int and modulo it.
38+
#
39+
# Time complexity: O(n) - Where n is the number of binary digits of the
40+
# result string.
41+
# Space complexity: O(n) - We need to generate a string of size n binary
42+
# digits.
43+
#
44+
# Runtime: 2449 ms, faster than 55.91%
45+
# Memory Usage: 15.9 MB, less than 22.05%
46+
class ListComprehension:
47+
def concatenatedBinary(self, n: int) -> int:
48+
# Initialize a string result.
49+
s = ""
50+
# Iterate over 1..n
51+
for num in range(1, n + 1):
52+
# Add the binary representation of num to s.
53+
s += bin(num)[2:]
54+
# Convert s to int and modulo 10^9 + 7
55+
return int(s, 2) % (10**9 + 7)
56+
57+
58+
# Iterate over the sequence 1..n, keeping track of the current result
59+
# as an integer. For each value, calculate the number of bits of its
60+
# binary representation, shift the result bits that many positions to
61+
# the left and add the current value.
62+
#
63+
# Time complexity: O(n) - Where n is the number of values in the input.
64+
# Space complexity: O(1) - We are only storing two integer values in
65+
# memory.
66+
#
67+
# Runtime: 1524 ms, faster than 82.17%
68+
# Memory Usage: 13.9 MB, less than 62.02%
69+
class BitCountIntSum:
70+
def concatenatedBinary(self, n: int) -> int:
71+
mod = 10**9 + 7
72+
# Initialize an int result.
73+
res = 0
74+
# Initialize the count of bits of the current number.
75+
bit_count = 0
76+
# Iterate over 1..n
77+
for num in range(1, n + 1):
78+
# Every time we find a power of 2, increase the bit count.
79+
if (num & (num - 1)) == 0:
80+
bit_count += 1
81+
# Shift the current bits of res left to accommodate the
82+
# number of bits of the coming value.
83+
res = ((res << bit_count) + num) % mod
84+
# Convert s to int and modulo 10^9 + 7
85+
return res
86+
87+
88+
# TODO study the O(log(n)) solutions below.
89+
90+
# The next three solutions are not my own code, I added them here for
91+
# completeness and to study them at a later point.
92+
93+
# https://leetcode.com/problems/concatenation-of-consecutive-binary-numbers/discuss/963549/
94+
class MtrxMultiplication:
95+
def concatenatedBinary(self, n: int) -> int:
96+
def multiply(X, Y):
97+
return [
98+
[
99+
sum(a * b for a, b in zip(X_row, Y_col)) % 1000000007
100+
for Y_col in zip(*Y)
101+
]
102+
for X_row in X
103+
]
104+
105+
ans, acc, level = [[1], [2], [1]], 1, 1
106+
while acc < n:
107+
M = 2 ** (level + 1)
108+
109+
# number of matrix production in this level
110+
x = take = min(n, M - 1) - acc
111+
mat = [[M, 1, 0], [0, 1, 1], [0, 0, 1]]
112+
113+
# for example
114+
# num^13 = num * num^4 * num^8
115+
# num^6 = num^2 * num^4
116+
while x > 0:
117+
if x & 1:
118+
ans = multiply(mat, ans)
119+
mat, x = multiply(mat, mat), x >> 1
120+
121+
acc, level = acc + take, level + 1
122+
123+
return ans[0][0]
124+
125+
126+
# https://leetcode.com/problems/concatenation-of-consecutive-binary-numbers/discuss/963886/
127+
class GeomProgression:
128+
def concatenatedBinary(self, n: int) -> int:
129+
MOD = 10**9 + 7
130+
131+
def modInverse(n):
132+
return pow(n, MOD - 2, MOD)
133+
134+
def sumGeometricSeries(r, n):
135+
return (pow(r, n, MOD) - 1) * modInverse(r - 1)
136+
137+
def sumBinaryOfLength(n, r):
138+
res = pow(2, n - 1, MOD) * sumGeometricSeries(
139+
pow(2, n, MOD), r - pow(2, n - 1, MOD) + 1
140+
)
141+
res %= MOD
142+
res += (
143+
sumGeometricSeries(pow(2, n, MOD), r - pow(2, n - 1, MOD) + 1)
144+
- 1
145+
- (r - pow(2, n - 1, MOD))
146+
) * modInverse(pow(2, n, MOD) - 1)
147+
return res % MOD
148+
149+
curr_size = 1
150+
res = 0
151+
for b in range(n.bit_length(), 0, -1):
152+
res += sumBinaryOfLength(b, min(n, pow(2, b) - 1)) * curr_size
153+
res %= MOD
154+
curr_size *= pow(
155+
2, (min(n, pow(2, b) - 1) - pow(2, b - 1) + 1) * b, MOD
156+
)
157+
curr_size %= MOD
158+
return (res + MOD) % MOD
159+
160+
161+
# https://leetcode.com/problems/concatenation-of-consecutive-binary-numbers/discuss/1037323/
162+
#
163+
# Time complexity: O(log^2 n)
164+
# Space complexity; O(1) ?
165+
#
166+
# Runtime: 120 ms, faster than 99.22%
167+
# Memory Usage: 13.8 MB, less than 79.84%
168+
class GemProg2:
169+
def concatenatedBinary(self, n: int) -> int:
170+
def bin_pow(num):
171+
return [1 << i for i, b in enumerate(bin(num)[:1:-1]) if b == "1"]
172+
173+
ans, MOD, q = 0, 10**9 + 7, len(bin(n)) - 3
174+
175+
B = bin_pow((1 << q) - 1) + bin_pow(n - (1 << q) + 1)[::-1]
176+
C = list(range(1, q + 1)) + [q + 1] * (len(B) - q)
177+
D = list(accumulate(i * j for i, j in zip(B[::-1], C[::-1])))[::-1][
178+
1:
179+
] + [0]
180+
181+
for a, b, c, d in zip(accumulate(B), B, C, D):
182+
t1 = pow(2, b * c, MOD) - 1
183+
t2 = pow(pow(2, c, MOD) - 1, MOD - 2, MOD)
184+
ans += t2 * ((a - b + 1 + t2) * t1 - b) * pow(2, d, MOD)
185+
186+
return ans % MOD
187+
188+
189+
def test():
190+
executors = [
191+
OneLine,
192+
ListComprehension,
193+
BitCountIntSum,
194+
MtrxMultiplication,
195+
GeomProgression,
196+
GemProg2,
197+
]
198+
tests = [
199+
[1, 1],
200+
[3, 27],
201+
[12, 505379714],
202+
[23032, 659725770],
203+
]
204+
for executor in executors:
205+
start = timeit.default_timer()
206+
for _ in range(1):
207+
for col, t in enumerate(tests):
208+
sol = executor()
209+
result = sol.concatenatedBinary(t[0])
210+
exp = t[1]
211+
assert result == exp, (
212+
f"\033[93m» {result} <> {exp}\033[91m for"
213+
+ f" test {col} using \033[1m{executor.__name__}"
214+
)
215+
stop = timeit.default_timer()
216+
used = str(round(stop - start, 5))
217+
cols = "{0:20}{1:10}{2:10}"
218+
res = cols.format(executor.__name__, used, "seconds")
219+
print(f"\033[92m» {res}\033[0m")
220+
221+
222+
test()

0 commit comments

Comments
 (0)