diff --git a/src/main.rs b/src/main.rs index f296839..8fb4b01 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,5 @@ fn main() { - aoc_2018::tasks::day02::task1(); - aoc_2018::tasks::day02::task2(); + // aoc_2018::tasks::day02::task1(); + // aoc_2018::tasks::day02::task2(); + aoc_2018::tasks::day02::task2_linear(); } diff --git a/src/tasks/day02.rs b/src/tasks/day02.rs index 44eef79..9c77332 100644 --- a/src/tasks/day02.rs +++ b/src/tasks/day02.rs @@ -1,3 +1,5 @@ +use std::collections::HashMap; +use std::collections::HashSet; use utils; pub fn task1() { @@ -48,3 +50,105 @@ pub fn task2() { println!("Part 2: None found!"); } + +pub fn task2_linear() { + let input = utils::read_file("input/day02.txt"); + + // first order of business: create a tree where each input line is sorted + // into every nodes same_prefix, if the path leading from the root to that + // has that prefix. + let mut root = Node::default(); + for id in input.lines() { + add_id_to_tree(&mut root, &id); + } + + // find a match.. + let result = find_some_match(&root); + println!("{:?}", result); +} + +fn find_some_match(node: &Node) -> Option { + if let Some(result) = check_children_for_match(&node) { + return Some(result); + } else { + for child in node.outgoing.values() { + if let Some(result) = find_some_match(&child) { + return Some(result); + } + } + None + } +} + +/// Checks all IDs that have the prefix of this node if they are a match. +/// For this first for every child we look at its collected IDs - those +/// are the potential candidates, e.g. an ID that is in the 'e' child and +/// one that is in the 'f' child, if both have the same suffix. +/// +/// We know that there is a unique match. Therefore we can sort out all +/// suffixes that appear more than once in a child node. Then we look at +/// all possible suffixes from all child nodes. If one suffix appears exactly +/// twice, we have a match. +fn check_children_for_match<'a>(node: &Node<'a>) -> Option { + let edges: Vec<_> = node.outgoing.keys().collect(); + // create a set of candidate suffixes for each edge + let suffix_candidates: HashMap> = edges + .iter() + .map(|c| { + let mut suffix_count = HashMap::<&str, HashSet<&str>>::new(); + let ref ids = node.outgoing.get(&c).unwrap().same_prefix; + for id in ids { + suffix_count + .entry(&id[node.depth + 1..]) + .or_insert(HashSet::new()) + .insert(id); + } + + ( + **c, + suffix_count + .iter() + .filter(|(_, count)| count.len() == 1) + .map(|(suffix, _)| *suffix) + .collect(), + ) + }).collect(); + // go over all suffixes and count their occurences. If # = 2, match! + let mut suffix_counter: HashMap<&str, usize> = HashMap::new(); + for suffix_set in suffix_candidates.values() { + for suffix in suffix_set { + *suffix_counter.entry(suffix).or_insert(0) += 1; + } + } + if let Some(suffix) = + suffix_counter + .iter() + .find_map(|(suffix, count)| if *count == 2 { Some(suffix) } else { None }) + { + Some(format!("{}{}", node.prefix, &suffix)) + } else { + None + } +} + +#[derive(Default, Debug)] +struct Node<'a> { + depth: usize, + prefix: &'a str, + same_prefix: HashSet<&'a str>, + outgoing: HashMap>, +} + +fn add_id_to_tree<'a>(root: &mut Node<'a>, id: &'a str) { + let mut current = root; + current.same_prefix.insert(&id); + for (i, c) in id.chars().enumerate() { + { + let mut next = current.outgoing.entry(c).or_insert(Node::default()); + next.depth = i + 1; + next.same_prefix.insert(&id); + next.prefix = &id[..=i]; + } + current = { current }.outgoing.get_mut(&c).unwrap(); + } +}