4
votes
Day 3: Lobby
Today's problem description: https://adventofcode.com/2025/day/3
Please post your solutions in your own top-level comment. Here's a template you can copy-paste into your comment to format it nicely, with the code collapsed by default inside an expandable section with syntax highlighting (you can replace python with any of the "short names" listed in this page of supported languages):
<details>
<summary>Part 1</summary>
```python
Your code here.
```
</details>
Part 1
Since there are only two digits to search, it is absolutely possible to just check all 2-digit combinations in each string and just take the maximum to reach the answer.Part 2
Okay so we can't just take the maximum over all 12 digit combinations (at least if we want to have the program run within a reasonable amount of time, though I think a sufficiently optimized brute force wouldn't take our entire lifetime?).The first simple enough solution I could come up with was to maintain an array that keeps track of the largest K-digit number that can be formed from the given digits, from 0 to 12 digits (yes, the 0th element is always 0 but I will eat a few bytes of wasted memory to avoid weird off-by-one situations). This array starts with all 0s, but we go left to right and analyzing each new digit of the digit string to update our array, ending with an array with the true answer in the 12th element.
When we look at each new digit, we can update our array by seeing that each largest K-digit number either doesn't use the rightmost digit or it does use this rightmost digit.
If it doesn't, then the answer is unchanged, since we already knew the largest K-digit number without the rightmost digit.
If it does, then we consider what the first K-1 digits would look like, and realize that this itself is a number, in fact that it's the largest K-1 digit number that could be formed without the rightmost digit (what
planningluck! We already have that in our array!)To cover both options, we can simply take the max over these (and take care for the order of operations, since an in-place array update might destroy that "K-1 digit number" information) and repeat for all K and all the way from left to right to get the full answer.
(I will note that the kids call this algorithm strategy Dynamic Programming, and given that it has a fancy name I'm not convinced it's the simplest algorithm.)
Part 1/2 Code (C++)
But can we do it *faster*?
If you do a bit of analysis on the above Part 2 solution, you'll recognize to solve the generalized problem of finding the maximum K-digit subsequence on a string of N digits, using our old friend Big O notation this solution takes O(NK) time. There is, however, a theoretically faster solution which uses a completely different approach.We instead observe that, for numbers with the same digit, numbers with larger first digits are larger, no matter what digits follow (for example 20000 > 19999, despite 199 having lots more 9s).
This gives us a different solution: If we just seek out the biggest leftmost digits and merely ensure that we can fill out the remaining digits, we get another solution that may be even faster:
Starting from the very left of the digit string, move forwards to the first 9 and see if there are enough remaining digits to build out the rest of the number (this is actually just an string index check, since you can always fill out a number by just taking all the digits after it). If it works, take it and continue building the number after the 9. If the 9 doesn't work (or there are no 9s in the string), try the next 8, then the next 7, etc. (you're not going to exhaust all the digits unless you're trying to build a number with more than N digits, which is easy to check).
Repeating this enough times, we will eventually end up with enough digits for a number.
But is it faster?
At first it doesn't look like it's faster, because we have to seek out the next digit each time, and that would make it O(NK) like before. But we can make an optimization that saves a ton of time on those seeks: just pre-compute for each position where the next occurrence of each digit is, and those seeks become O(1) array lookups.
Well that's a new problem: how do we pre-compute at each position where the next occurrence of each digit is?
The secret is to build this pre-computed array from right-to-left. Now the next occurrence of each digit (left-to-right) is just the most recently seen occurrence of each digit (right-to-left), and we can just update each value right-to-left as we see it.
This precomputation takes O(10 N) = O(N) time, and now that we only need to do an array lookup to build our number of K digits, the full solution takes O(10 N+10 K) = O(N+K) = O(N) time (remembering that K <= N in any reasonable version of this problem), which is definitely the fastest we can go.
Bonus problem: What if the base isn't 10? Given a N-digit string in base M, this solution will take O(NM) time. Can you find an even faster solution that covers this case? (I think there is one, but the solution that comes to me is exponentially more horrible and contains some super weird ideas).
Bit of a better day, as I guessed Part 2 so was already planning out the algorithm. My first thought was a DP solution (which napkin-math suggests might have worked?), but figured out a better approach instead. Went back and refactored to add a couple new utilities and make the main solver tail-recursive.
I got spooked at first thinking it might be 2D arrays and realized I'll need to read up to figure out how best to handle that, as it's sure to be coming in the next few days.
Prolog Solution
Obvious dynamic programming problem for today. You only need to keep track of maximum joltage you can get using 1 to n previous batteries and when adding one more battery, you update the max of size k using if you can get a better value from using the max of size k-1 and the current battery.
It's my cleanest implementation so far, but that's mostly because it's just so short.
Part 1 and 2 (Rust)