开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第9天,点击查看活动详情
- Advent of Code 2020 Day9 译文(用 Rust 实现 Advent of Code 2020 第9天)
- 原文链接:fasterthanli.me/series/adve…
- 原文作者:Amos
- 译文来自:github.com/suhanyujie/…
- 译者:suhanyujie
- ps:水平有限,如有不当之处,欢迎指正
- 标签:Rust,advent of code, algo
第 9 天的问题描述有点复杂 —— “啊,也许这就是为什么我通常不做 Advent of Code”的问题所在,但无论如何,还是尝试一下。
我们有像这样的一系列数字:
35
20
15
25
47
40
62
55
65
95
102
117
150
182
127
219
299
277
309
576
前 N 个数字是“元值”,N 后面的数字必须是前面两个数字的和组成。
对于上面的例子,N 是 5。所以,可能有一个聪明和快速的方法来解决这个问题,但我将再次尝试一个简单和正确的解决方案。
我喜欢这个问题的一点是,它可以让我使用一些很酷的方法。
们要遍历 n+1 大小的窗口 —— 所以这里,元素 0..=5 (包括 5) ,然后是 1..=6,然后是 2..=7,以此类推。然后我们会得到元素 0..5,1..6,2..7 等所有可能组合(独家),看看这些组合的总和是否等于我们窗口中的最后一个元素。
use itertools::Itertools;
fn main() {
let numbers = include_str!("input.txt")
.lines()
.map(|x| x.parse::<usize>().unwrap())
.collect::<Vec<_>>();
let n = 5;
let answer = numbers.windows(n + 1).find_map(|s| {
if (&s[..n])
.iter()
.tuple_combinations()
.any(|(a, b)| a + b == s[n])
{
None
} else {
Some(s[n])
}
});
println!("answer = {:?}", answer);
}
$ cargo run --quiet
answer = Some(127)
酷熊:酷,这个结果符合预期! 我想我们已经完成了?
让我们试试 n=25 的输入:
$ cargo run --quiet
answer = Some(26134589)
嘿,这是正确的答案!
酷熊:继续!
第二部分
下一部分要求我们在列表中找到“至少两个数字”的连续集合,它们的和与步骤 1 中的无效数字相加”。
这也不是什么难事。我们可以做的一件事是把所有 2 号的窗口加起来,然后把所有 3 号的窗口加起来,以此类推 —— 然后把所有这些窗口中的项加起来。一旦我们找到答案,就可以了!
let answer = answer.unwrap();
let answer2 = (2..numbers.len())
.into_iter()
.map(|n| numbers.windows(n).map(|s| s.iter().sum::<usize>()))
.flatten()
.find(|&n| n == answer);
println!("answer2 = {:?}", answer2);
$ cargo run --quiet
answer2 = Some(26134589)
我们确实找到了一组连续的数字,它们的和跟我们在第一部分找到的答案是一样的,但我们不知道这组集合在哪里或者有多大。
让我们解决这个问题:
let answer2 = (2..numbers.len())
.into_iter()
.map(|n| {
numbers
.windows(n)
.enumerate()
.map(move |(i, s)| (n, i, s.iter().sum::<usize>()))
})
.flatten()
.find(|&(_, _, sum)| sum == answer);
let (n, i, _) = answer2.unwrap();
let set = &numbers[i..][..n];
println!("sum({:?}) = {}", set, answer);
$ cargo run --quiet
sum([1503494, 978652, 1057251, 1142009, 1239468, 1407633, 1048040, 1484541, 1164289, 1432864, 1792914, 2556472, 2464510, 1750429, 1753116, 1673488, 1685419]) = 26134589
这样好多了。
现在我们需要把这个连续范围内最小和最大的数相加:
let answer3 = set.iter().max().unwrap() + set.iter().min().unwrap();
dbg!(answer3);
$ cargo run --quiet
[src/main.rs:39] answer3 = 3535124
啊,我们完成了! 很容易,看来我的担心是多余的。