From 6977c039fa176ab791d2cc8d9509452977e5457b Mon Sep 17 00:00:00 2001 From: rolv Date: Sat, 12 Jul 2025 13:27:13 +0100 Subject: [PATCH 1/4] perf: improve performance of 2018 day 2 part 2 --- src/year2018/day02.rs | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/src/year2018/day02.rs b/src/year2018/day02.rs index 75c6e9e9..48d73bd1 100644 --- a/src/year2018/day02.rs +++ b/src/year2018/day02.rs @@ -1,5 +1,4 @@ //! # Inventory Management System -use crate::util::hash::*; pub fn parse(input: &str) -> Vec<&[u8]> { input.lines().map(str::as_bytes).collect() @@ -44,29 +43,32 @@ pub fn part1(input: &[&[u8]]) -> u32 { } pub fn part2(input: &[&[u8]]) -> String { - let width = input[0].len(); + // Manually compare all IDs, as it is faster than other methods considering there are so few total IDs + for i in 0..input.len() { + for ii in i + 1..input.len() { + let id1 = input[i]; + let id2 = input[ii]; - let mut seen = FastSet::with_capacity(input.len()); - let mut buffer = [0; 32]; - - // Use a set to check for duplicates after replacing a single character with '*' in each column. - for column in 0..width { - for &id in input { - buffer[0..width].copy_from_slice(id); - buffer[column] = b'*'; + let mut diff = false; + for (a, b) in id1.iter().zip(id2) { + if a != b { + if diff { + diff = false; + break; + } + diff = true; + } + } - if !seen.insert(buffer) { - // Convert to String - return buffer + if diff { + // Build the string of characters which are the same between both IDs + return id1 .iter() - .filter(|&&b| b.is_ascii_lowercase()) - .map(|&b| b as char) + .zip(id2) + .filter_map(|(a, b)| if a == b { Some(char::from(*a)) } else { None }) .collect(); } } - - seen.clear(); } - unreachable!() } From 22569fd240430bef7fff435f6d2a551de8c9a3ff Mon Sep 17 00:00:00 2001 From: rolv Date: Sat, 12 Jul 2025 13:35:04 +0100 Subject: [PATCH 2/4] fix: clippy lint --- src/year2018/day02.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/year2018/day02.rs b/src/year2018/day02.rs index 48d73bd1..cbcf3613 100644 --- a/src/year2018/day02.rs +++ b/src/year2018/day02.rs @@ -65,7 +65,7 @@ pub fn part2(input: &[&[u8]]) -> String { return id1 .iter() .zip(id2) - .filter_map(|(a, b)| if a == b { Some(char::from(*a)) } else { None }) + .filter_map(|(a, b)| (a == b).then(|| char::from(*a))) .collect(); } } From f6c50ce45bb260ec46bc0c274c5b10bc472cabd2 Mon Sep 17 00:00:00 2001 From: rolv Date: Sat, 12 Jul 2025 13:36:59 +0100 Subject: [PATCH 3/4] fix: clippy lint for the clippy lint --- src/year2018/day02.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/year2018/day02.rs b/src/year2018/day02.rs index cbcf3613..2fce81b7 100644 --- a/src/year2018/day02.rs +++ b/src/year2018/day02.rs @@ -65,7 +65,8 @@ pub fn part2(input: &[&[u8]]) -> String { return id1 .iter() .zip(id2) - .filter_map(|(a, b)| (a == b).then(|| char::from(*a))) + .filter(|&(a, b)| a == b) + .map(|(a, _)| char::from(*a)) .collect(); } } From 845d76028d549fb105f2a5d0d9223e79af050bc7 Mon Sep 17 00:00:00 2001 From: rolv Date: Sat, 12 Jul 2025 19:04:58 +0100 Subject: [PATCH 4/4] refactor: revert back to the original approach - but only insert the prefix and suffix of IDs into the hashset --- src/year2018/day02.rs | 40 +++++++++++++++++----------------------- 1 file changed, 17 insertions(+), 23 deletions(-) diff --git a/src/year2018/day02.rs b/src/year2018/day02.rs index 2fce81b7..b2c6dfb1 100644 --- a/src/year2018/day02.rs +++ b/src/year2018/day02.rs @@ -1,5 +1,7 @@ //! # Inventory Management System +use crate::util::hash::*; + pub fn parse(input: &str) -> Vec<&[u8]> { input.lines().map(str::as_bytes).collect() } @@ -43,33 +45,25 @@ pub fn part1(input: &[&[u8]]) -> u32 { } pub fn part2(input: &[&[u8]]) -> String { - // Manually compare all IDs, as it is faster than other methods considering there are so few total IDs - for i in 0..input.len() { - for ii in i + 1..input.len() { - let id1 = input[i]; - let id2 = input[ii]; + let width = input[0].len(); - let mut diff = false; - for (a, b) in id1.iter().zip(id2) { - if a != b { - if diff { - diff = false; - break; - } - diff = true; - } - } + let mut seen = FastSet::with_capacity(input.len()); - if diff { - // Build the string of characters which are the same between both IDs - return id1 - .iter() - .zip(id2) - .filter(|&(a, b)| a == b) - .map(|(a, _)| char::from(*a)) - .collect(); + // Use a set to check for duplicates by comparing the prefix and suffix of IDs excluding one + // column at a time. + for column in 0..width { + for &id in input { + let prefix = &id[..column]; + let suffix = &id[column + 1..]; + + if !seen.insert([prefix, suffix]) { + // Convert to String + return prefix.iter().chain(suffix).cloned().map(char::from).collect(); } } + + seen.clear(); } + unreachable!() }