Skip to content

Commit 941e77b

Browse files
committed
Day 16 part 2 method 2 optimized
1 parent fbfa52b commit 941e77b

File tree

2 files changed

+21
-8
lines changed

2 files changed

+21
-8
lines changed

day16/README.md

+13-1
Original file line numberDiff line numberDiff line change
@@ -125,4 +125,16 @@ It took me like 5 minutes to write this:
125125
```
126126
And it takes forever trying to finish the first iteration. When I look at the code, the complexity analyse above is wrong, it actually needs `100*(L/2)^2 = 10^15` additions to finish.
127127

128-
Lesson learnt: *sometimes we can just let the computer do the computing, but sometimes maths is helpful to solve impossible computing problem*.
128+
Lesson learnt: *sometimes we can just let the computer do the computing, but sometimes maths is helpful to solve impossible computing problem*.
129+
130+
PS: now I got two stars, I went take a look on subreddit, and found that my method above is far from optimized. Each iteration could be written as:
131+
```python
132+
for _ in range(N_ITERATION):
133+
output[-1] = input[-1]
134+
for j in range(L2-2, -1, -1):
135+
output[j] = (output[j+1] + input[j]) % 10
136+
input = output.copy()
137+
```
138+
We reduced the complexity of each iteration from O(L^2) to O(L), and PyPy finished in 0.57s instead of 3.6s (but CPython is slower: 6.4s). We can see this trick is many place, to do sub array sum in O(1) (with O(L) preparation time) instead of O(L) without preparation.
139+
140+
A user, bla2, cleverly [remarked](https://www.reddit.com/r/adventofcode/comments/ebxz7f/2019_day_16_part_2_visualization_and_hardmode/) that we can apply this trick to calculate the full message. The complexity per iteration is now O(LlogL) instead of O(L). With `L = 6.5*10^6` and 100 iteration, Python will be two slow and his C implementation finished in 50s.

day16/d16.py

+8-7
Original file line numberDiff line numberDiff line change
@@ -40,15 +40,16 @@ def part2_2(input):
4040
sys.exit('Oh my, I have no idea deal with that offset.')
4141

4242
input = list(map(int, (input*N_REPEAT)[offset:]))
43-
output = input.copy()
44-
for i in range(N_ITERATION):
45-
print('Iteration', i, len(input))
46-
for j in range(len(input)):
47-
output[j] = sum(input[j:]) % 10
43+
L2 = len(input)
44+
output = [0]*L2
45+
for _ in range(N_ITERATION):
46+
output[-1] = input[-1]
47+
for j in range(L2-2, -1, -1):
48+
output[j] = (output[j+1] + input[j]) % 10
4849
input = output.copy()
49-
return ''.join(map(str, output))
50+
return ''.join(map(str, output))[0:8]
5051

5152

5253
print('Part 1:', get_output(input, N_ITERATION)[0:8])
5354
print('Part 2:', part2(input))
54-
#print('Part 2:', part2_2(input))
55+
print('Part 2:', part2_2(input))

0 commit comments

Comments
 (0)