1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
use crate::common::parser::parse_lines;
use crate::input::Input;
fn subsequence_summing_to<T>(sequence: &[T], desired_sum: T) -> Option<&[T]>
where
T: std::ops::AddAssign + Copy + PartialEq + PartialOrd + std::ops::SubAssign,
{
let mut window_start = 0;
let mut window_sum = sequence[window_start];
for window_end in 1..sequence.len() {
if window_sum == desired_sum {
return Some(&sequence[window_start..window_end]);
}
window_sum += sequence[window_end];
while window_sum > desired_sum && window_start < window_end - 1 {
window_sum -= sequence[window_start];
window_start += 1;
}
}
None
}
pub fn solve(input: &mut Input) -> Result<u64, String> {
const PREAMBLE_LENGTH: usize = 25;
let numbers = parse_lines::<u64>(input.text)?;
if numbers.len() <= PREAMBLE_LENGTH {
return Err(format!("Too few input numbers ({})", numbers.len()));
}
let invalid_number = numbers
.iter()
.enumerate()
.skip(PREAMBLE_LENGTH)
.find_map(|(idx, &number)| {
for j in (idx - PREAMBLE_LENGTH)..idx {
for k in j + 1..idx {
if numbers[j] + numbers[k] == number {
return None;
}
}
}
Some(number)
})
.ok_or_else(|| "No invalid number".to_string())?;
if input.is_part_one() {
return Ok(invalid_number);
}
subsequence_summing_to(&numbers, invalid_number)
.map(|subsequence| {
let (min, max) = subsequence
.iter()
.fold((u64::MAX, u64::MIN), |(min, max), &number| {
(std::cmp::min(min, number), std::cmp::max(max, number))
});
min + max
})
.ok_or_else(|| format!("No contiguous set summing to {}", invalid_number))
}
#[test]
pub fn tests() {
use crate::input::{test_part_one, test_part_two};
let real_input = include_str!("day09_input.txt");
test_part_one!(real_input => 50_047_984);
test_part_two!(real_input => 5_407_707);
}