跳到主要内容

Advent of Code 2023

· 阅读需 5 分钟

Advent of Code 是一个为期 25 天的编程挑战赛,从 12 月 1 日持续到 25 日,每天的东部时间凌晨(北京时间的午后 1 点)发布一道题目。不限制语言,不考究算法,只要能提交正确答案,都可以算作通过并得分。这个活动从 2015 年开始,已经成为了全球程序员的年度盛事之一。

每天的题目会分为两个部分,全部完成可得两颗金星,只完成第一部分则获得一颗银星。解题的时间越早,排名越靠前。第一个解决问题的将获得 100 颗星星,接下来每位递减一颗星星,直到递减到一颗星。也就是说每天最多能获得 200 颗星星。

只有少数大佬是为了冲榜,普通人可以一天一语言完成题目。也可以用奇技淫巧解决问题。可以在 r/adventofcode 上看到各种奇技淫巧。

代码:https://github.com/Selflocking/Code/tree/master/others/AOC2023

Day 1 (C++)

Part 1

给你多行字符串,请找出每行中第一个和最后一个数字,将其组成一个二位数。然后将所有的二位数相加。

例如:

1abc2
pqr3stu8vwx
a1b2c3d4e5f
treb7uchet

第一行中的数字是 12,第二行中的数字是 38,第三行中的数字是 15,第四行中的数字是 77。将这些数字相加,得到 142。

第一部分简单,只需要从行首遍历到行未,找到第一个数字和最后一个数字,然后组成二位数相加即可。

#include <bits/stdc++.h>

using namespace std;

int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);

fstream in;
in.open("input.txt");
if (!in.is_open()) {
cerr << "Failed to open file" << endl;
exit(-1);
}

int ans = 0;
while (!in.eof()) {
string s;
in >> s;

int first = -1;
int last = -1;
for (auto c : s) {
if (c >= '0' && c <= '9') {
if (first == -1) {
first = c - '0';
}
last = c - '0';
}
}

if (first == -1 || last == -1) {
cout << "error";
}

ans += first * 10 + last;
}
cout << ans << endl;
return 0;
}

Part 2

day1-part2

one, two, three, four, five, six, seven, eight, 和 nine 这些单词也算数字,例如 two1nine 组成的数字是 29。求所有行组成的数字的和。

这部分我做了很久,我最开始的思路是:对于每一行,先找第一个数字,再找第二个数字。接着找英文单词数字,使用string::find 函数找每个单词的位置,比较哪个才是最小的,哪个是最大的。但是我忽略了每行可能有多个同一单词的情况,例如 one2one, 正确应该是 11, 我的程序输出的是 12。

看了下 Reddit 上的讨论,有些人是从头遍历字符串,遇到 one 等就将其替换成 1。但是会遇到 twone 这种情况。

最后我的做法是先找到第一个单词,接着将字符串反转,找第一个单词。

#include <algorithm>
#include <bits/stdc++.h>
#include <cctype>
#include <fstream>
#include <iostream>
#include <unordered_map>

using namespace std;

auto NumToString = unordered_map<int, string>{
{1, "one"}, {2, "two"}, {3, "three"}, {4, "four"}, {5, "five"},
{6, "six"}, {7, "seven"}, {8, "eight"}, {9, "nine"}};

class Num {
public:
bool used = false;
string::size_type loc = 0;
int value = -1;
bool operator<(const Num &other) const {
return this->loc < other.loc;
}
};

int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);

fstream in;
// in.open("example2.txt");
in.open("input.txt");
if (!in.is_open()) {
exit(-1);
}

int ans = 0;
while (!in.eof()) {
string s;
in >> s;
Num first;
Num last;
for (string::size_type i = 0; i < s.size(); ++i) {
auto &c = s[i];
if (c >= '0' && c <= '9') {
Num value{true, i, c - '0'};
if (!first.used) {
first = value;
}
last = value;
}
}

for (auto [n, str] : NumToString) {
auto loc = s.find(str);
if (loc != string::npos) {
Num value{true, loc, n};
if (!first.used) {
first = value;
} else {
first = min(first, value);
}
}
}

reverse(s.begin(), s.end());
for (auto [n, str] : NumToString) {
reverse(str.begin(), str.end());
auto loc = s.find(str);
if (loc != string::npos) {
Num value{true, s.size() - loc - str.size(), n};
if (!last.used) {
last = value;
} else {
last = max(last, value);
}
}
}

if (!first.used || !last.used) {
cerr << "error";
}

auto add = first.value * 10 + last.value;
ans += add;
}
cout << ans << endl;
return 0;
}