Encoding Error
2020-12-09 Original Prompt Part 1
Once again, we don’t have to do anything too fancy here. Summing numbers is fast, so it’s ok if we do it a lot. Combining that with a set for fast lookup and we can safely repeat a lot of work.
On each step of our loop, we want an element and all of the sums for the 25 previous elements. I use a PREAMBLE_SIZE variable so I could easily set it to 5 and 25 for testing as needed, but it’s not super necessary.
We’ll look at each index starting at PREAMBLE_SIZE:
for i in range(PREAMBLE_SIZE, len(self.input)):Next, the sums. Just like day 1, we’ll reach for itertools.combinations:
sums = { sum(pair) for pair in combinations(self.input[i - PREAMBLE_SIZE : i], 2)}This strikes me as a great example of Python code being both readable and concise (not to toot my own horn). Each piece should be familiar:
self.input[i - PREAMBLE_SIZE : i]gets the 25 elements directly before our indexcombinations(X, 2)gets us all of our pairs (like[(1, 2), (2, 3), (1, 3)]){sum(pair) for pair in X}gives us a set of each of those sums
Lastly, we run through our loop and return the number that isn’t in the set:
if self.input[i] not in sums: return self.input[i]Part 2
This is another day where my solve function comes into play (running both parts at once instead of doing it separately). The answer from part_1 is stored as bad_num.
This will be another brute-force approach. We have to step very slowly through the input, taking an increasingly large range until we meet or exceed the bad_num.
We start at the very beginning and initialize a running sum:
for range_start in range(len(self.input)): running_sum = self.input[range_start] = self.input[range_start]Then, we iterate again (which feels unavoidable at this point), incrementally summing the ongoing range until either:
running_sum == bad_num, in which case we can finishrunning_sum > bad num, so we have to start a new range
for range_end in range(range_start + 1, len(self.input)): running_sum += self.input[range_end] if running_sum == bad_num: continuous_range = self.input[range_start : range_end + 1] return bad_num, min(continuous_range) + max(continuous_range) if running_sum > bad_num: breakThis is another example where we can get away with returning from deep in a loop because we know we’ll get there sometime. Otherwise we’d need a plan for if we fail-to-find.