aoc/year2018/
day02.rs

1//! # Inventory Management System
2use crate::util::hash::*;
3
4pub fn parse(input: &str) -> Vec<&[u8]> {
5    input.lines().map(str::as_bytes).collect()
6}
7
8pub fn part1(input: &[&[u8]]) -> u32 {
9    let mut total_twos = 0;
10    let mut total_threes = 0;
11
12    for &id in input {
13        // Ids are lowercase ASCII only with cardinality of 26.
14        let mut freq = [0; 26];
15        let mut twos = 0;
16        let mut threes = 0;
17
18        for &b in id {
19            let index = (b - b'a') as usize;
20            let current = freq[index];
21
22            match current {
23                0 => (),
24                1 => twos += 1,
25                2 => {
26                    twos -= 1;
27                    threes += 1;
28                }
29                _ => threes -= 1,
30            }
31
32            freq[index] += 1;
33        }
34
35        if twos > 0 {
36            total_twos += 1;
37        }
38        if threes > 0 {
39            total_threes += 1;
40        }
41    }
42
43    total_twos * total_threes
44}
45
46pub fn part2(input: &[&[u8]]) -> String {
47    let width = input[0].len();
48
49    let mut seen = FastSet::with_capacity(input.len());
50    let mut buffer = [0; 32];
51
52    // Use a set to check for duplicates after replacing a single character with '*' in each column.
53    for column in 0..width {
54        for &id in input {
55            buffer[0..width].copy_from_slice(id);
56            buffer[column] = b'*';
57
58            if !seen.insert(buffer) {
59                // Convert to String
60                return buffer
61                    .iter()
62                    .filter(|&&b| b.is_ascii_lowercase())
63                    .map(|&b| b as char)
64                    .collect();
65            }
66        }
67
68        seen.clear();
69    }
70
71    unreachable!()
72}