diff --git a/src/euler32/src/main.rs b/src/euler32/src/main.rs index fa04099..d5fe85d 100644 --- a/src/euler32/src/main.rs +++ b/src/euler32/src/main.rs @@ -5,70 +5,83 @@ type Int = u32; const UPPER_BOUND: Int = 3_333; // because result must be a 4-digit number fn main() { + // prevent reallocation of these sets on every call in `are_pandigital` let mut buffer1 = HashSet::new(); let mut buffer2 = HashSet::new(); - let f = (1..UPPER_BOUND) - .filter(|n| { - let s = n.to_string(); - let hs = s.chars().collect::>(); - hs.len() == s.len() && !hs.contains(&'0') - }) - .collect::>() - .leak(); + let factors = get_suitable_factors(UPPER_BOUND); - let mut result = HashSet::new(); - for f1 in f.iter() { + let mut products_of_pandigital_triples = HashSet::new(); + for f1 in factors.iter() { let lower_bound = UPPER_BOUND / f1; - 'inner: for f2 in f.iter().skip_while(|i| **i < lower_bound) { - let p = f1 * f2; - if f1.len() + f2.len() + p.len() > 9 { + 'inner: for f2 in factors.iter().skip_while(|i| **i < lower_bound) { + let product = f1 * f2; + if f1.oom() + f2.oom() + product.oom() > 9 { break 'inner; } - if are_pandigital([f1, f2, &p], &mut buffer1, &mut buffer2) { - println!("{f1} {f2} {p}"); - result.insert(p); + if are_pandigital([f1, f2, &product], &mut buffer1, &mut buffer2) { + println!("{f1} {f2} {product}"); + products_of_pandigital_triples.insert(product); } } } - println!("{}", result.iter().sum::()); + println!("{}", products_of_pandigital_triples.iter().sum::()); } -fn are_pandigital(input: [∬ 3], accum: &mut HashSet, hs: &mut HashSet) -> bool { - accum.clear(); +fn get_suitable_factors(upper_bound: Int) -> &'static [Int] { + (1..upper_bound) + .filter(|number| { + let str = number.to_string(); + let set = str.chars().collect::>(); + // a suitable number must not contain `0`, and must have an unique digit at every + // position + set.len() == str.len() && !set.contains(&'0') + }) + .collect::>() + // leaking the vec is slightly faster than handling the vec + .leak() +} - let mut length = 0; +fn are_pandigital( + input: [∬ 3], + digits_in_numbers: &mut HashSet, + set_of_char_buffer: &mut HashSet, +) -> bool { + digits_in_numbers.clear(); + + let mut length_of_all_numbers = 0; for n in input { - hs.clear(); + set_of_char_buffer.clear(); let s = n.to_string(); - length += s.len(); + length_of_all_numbers += s.len(); s.chars().for_each(|c| { - hs.insert(c); + set_of_char_buffer.insert(c); }); - if s.len() != hs.len() { + if s.len() != set_of_char_buffer.len() { return false; } - for item in hs.iter() { - accum.insert(*item); + for item in set_of_char_buffer.iter() { + digits_in_numbers.insert(*item); } } - accum.len() == 9 && length == 9 && !accum.contains(&'0') + digits_in_numbers.len() == 9 && length_of_all_numbers == 9 && !digits_in_numbers.contains(&'0') } trait Length { - fn len(&self) -> usize; + fn oom(&self) -> usize; } impl Length for Int { - fn len(&self) -> usize { + // order of magnitude + fn oom(&self) -> usize { let mut tmp = 1; let mut oom = 1; while tmp - 1 < *self {