🎄 Advent of Code 2'023 - Day 01
Day 01: Trebuchet?!
* Cf. aoc. d. i xxiii
To solve the first day’s challenge, we need to find the first and last digit of each line, combine them, and then sum them all up with the result of the other lines. *
1abc2
pqr3stu8vwx
a1b2c3d4e5f
treb7uchet
Given the input 1abc2
: 1
and 2
are the first and last digits, respectively.
So we put them together and we get 12
. We do this for each line, and then we sum
them all up.
PARS I
tip
I’m going to be honest with you, It was quite a challenge to solve this problem. I’m not proficient in C++. I’m actually learning it as we go through the challenge, so I had to do a lot of research in between the solutions.
I’ve started by solving the problem for a single line. The logic is quite simple: we iterate over the line, and if the current character is a digit, we check if the first digit is empty. If it is, we assign the current character to it.
α
We always update the last digit with the current character, so at the end of the iteration, we’ll have the first and last digits of the line.
That looks good! We can solve the problem for a single line. Now we need to
make sure we can solve it for multiple lines. One way to do that is to calculate
and reset the first
and last
variables after each new line \n
.
β
#include<iostream>
#include<algorithm>
using namespace std;
class Solution {
public:
static int part1(string &input) {
int ans = 0;
char first = ' ';
char last = ' ';
for (char &i: input) {
// Reset first and last when we find a new line
if (i == '\n') {
if (first != ' ' && last != ' ') {
ans = (ans + (first - '0') * 10 + (last - '0'));
}
first = ' ';
last = ' ';
continue;
}
if (i >= '0' && i <= '9') {
if (first == ' ') first = i;
last = i;
};
}
ans = (ans + (first - '0') * 10 + (last - '0'));
return ans;
}
};
In that way we can solve the problem for multiple lines in O(n)
.
With that we unlock the second part of the challenge and won our first star! 🌟
PARS II
In the second part of the challenge, we discovered that the digit can actually be
spelled out with words. So both 1
and one
are valid digits.
The way I decided to go about it was to create a map with all the spelled out digits and their respective values * containing the numeric digit.
* Some people were having trouble with the overlapping digits.
For example twone
should be a match for 2
and 1
.
That means that we can’t just replace the whole spelled out digit, we need to
leave the chars that can be used to form other digits.
unordered_map<string, string> C = {
{"one", "o1e"},
{"two", "t2o"},
{"three", "t3e"},
{"four", "f4r"},
{"five", "f5e"},
{"six", "s6x"},
{"seven", "s7n"},
{"eight", "e8t"},
{"nine", "n9e"},
};
Now we can iterate over the map and replace the spelled out digits with their respective numeric digits.
for (auto &i: C) {
unsigned long pos = input.find(i.first);
while (pos != string::npos) {
input.replace(pos, i.first.size(), i.second);
pos = input.find(i.first);
}
}
Now we can use the same logic as before to find the first and last digits of each line and sum them up.
#include<iostream>
#include<algorithm>
using namespace std;
class Solution {
public:
static int part1(string &input) {
int ans = 0;
char first = ' ';
char last = ' ';
for (char &i: input) {
if (i == '\n') {
if (first != ' ' && last != ' ') {
ans = (ans + (first - '0') * 10 + (last - '0'));
}
first = ' ';
last = ' ';
continue;
}
if (i >= '0' && i <= '9') {
if (first == ' ') first = i;
last = i;
};
}
ans = (ans + (first - '0') * 10 + (last - '0'));
return ans;
}
static int part2(string &input) {
unordered_map<string, string> C = {
{"one", "o1e"},
{"two", "t2o"},
{"three", "t3e"},
{"four", "f4r"},
{"five", "f5e"},
{"six", "s6x"},
{"seven", "s7n"},
{"eight", "e8t"},
{"nine", "n9e"},
};
for (auto &i: C) {
unsigned long pos = input.find(i.first);
while (pos != string::npos) {
input.replace(pos, i.first.size(), i.second);
pos = input.find(i.first);
}
}
return part1(input);
}
};
And with that we unlock the second star! 🌟🌟
Click here to access the blogpost from @fefas
α) we could also try a two pointer approach to find the first and the last digits.
One pointer goes from right to left right++
, and the other goes left
to right left--
. They both would stop once they found a digit and don't
overlap with each other.
β) using a two pointers approach would make the solution more confusing and harder to understand, because we would need to track the single digits with the left pointer, and the double digits with the right pointer.