diff --git a/README.md b/README.md index 2562a95..f5bb334 100644 --- a/README.md +++ b/README.md @@ -13,8 +13,9 @@ Solutions for [Advent of Code](https://adventofcode.com/) in [Rust](https://www. | :---: | :---: | :---: | | [Day 1](./src/bin/01.rs) | `113.0µs` | `119.9µs` | | [Day 2](./src/bin/02.rs) | `54.7ms` | `71.6ms` | +| [Day 3](./src/bin/03.rs) | `802.9µs` | `131.1µs` | -**Total: 126.53ms** +**Total: 127.47ms** --- diff --git a/data/examples/03.txt b/data/examples/03.txt new file mode 100644 index 0000000..c9d476e --- /dev/null +++ b/data/examples/03.txt @@ -0,0 +1,5 @@ +987654321111111 +811111111111119 +234234234234278 +818181911112111 + diff --git a/src/bin/03.rs b/src/bin/03.rs new file mode 100644 index 0000000..a8a2994 --- /dev/null +++ b/src/bin/03.rs @@ -0,0 +1,95 @@ +advent_of_code::solution!(3); + +/// Find the maximum 2-digit number by selecting exactly 2 batteries from a bank +fn max_joltage_2(bank: &[u8]) -> u64 { + let mut max = 0u64; + + // For each position as the tens digit + for i in 0..bank.len() - 1 { + let tens = bank[i] as u64; + // Find max digit after position i + let units = *bank[i + 1..].iter().max().unwrap() as u64; + let joltage = tens * 10 + units; + max = max.max(joltage); + } + + max +} + +pub fn part_one(input: &str) -> Option { + let mut total = 0u64; + + for line in input.lines() { + let line = line.trim(); + if line.is_empty() { + continue; + } + + // Convert line to digits + let digits: Vec = line.chars().map(|c| c.to_digit(10).unwrap() as u8).collect(); + total += max_joltage_2(&digits); + } + + Some(total) +} + +/// Find the maximum k-digit number by selecting exactly k batteries from a bank +fn max_joltage_k(bank: &[u8], k: usize) -> u64 { + let n = bank.len(); + let mut result = 0u64; + let mut start = 0; + + // Greedily pick each of the k digits + for remaining in (1..=k).rev() { + // We can pick from [start, n - remaining] inclusive + let end = n - remaining; + + // Find the FIRST position of the max digit in this range + let mut best_pos = 0; + let mut best_digit = bank[start]; + for (i, &d) in bank[start..=end].iter().enumerate() { + if d > best_digit { + best_digit = d; + best_pos = i; + } + } + + result = result * 10 + best_digit as u64; + start = start + best_pos + 1; + } + + result +} + +pub fn part_two(input: &str) -> Option { + let mut total = 0u64; + + for line in input.lines() { + let line = line.trim(); + if line.is_empty() { + continue; + } + + let digits: Vec = line.chars().map(|c| c.to_digit(10).unwrap() as u8).collect(); + total += max_joltage_k(&digits, 12); + } + + Some(total) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_part_one() { + let result = part_one(&advent_of_code::template::read_file("examples", DAY)); + assert_eq!(result, Some(357)); + } + + #[test] + fn test_part_two() { + let result = part_two(&advent_of_code::template::read_file("examples", DAY)); + assert_eq!(result, Some(3121910778619)); + } +}