From 2b86db2532a701e4f2ba39d42f66c0db9c1e31a8 Mon Sep 17 00:00:00 2001 From: "Dr. Matthias Ratajczak" Date: Tue, 16 Aug 2022 17:06:48 +0200 Subject: [PATCH] performance optimization in 51 --- src/euler51/src/main.rs | 63 ++++++++++++++++++++++++----------------- 1 file changed, 37 insertions(+), 26 deletions(-) diff --git a/src/euler51/src/main.rs b/src/euler51/src/main.rs index 62fecd8..0beb462 100644 --- a/src/euler51/src/main.rs +++ b/src/euler51/src/main.rs @@ -1,6 +1,8 @@ extern crate combination; extern crate primes; +use std::process::exit; + use combination::PositionCombinations; use primes::Primes; @@ -23,37 +25,41 @@ const MIN_VALUE: Int = 100_000; const MAX_VALUE: Int = 999_999; const LENGTH: usize = 6; const MIN_LENGTH: usize = 2; +const TARGET_LENGTH: usize = 8; const MAX_LENGTH: usize = LENGTH - 1; const DIGITS: [u8; 10] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; fn main() { let all_primes = Primes::get_between(MIN_VALUE, MAX_VALUE); - let mut best_of_all_combinations = vec![]; + for pattern in PositionCombinations::new(MIN_LENGTH, MAX_LENGTH, LENGTH) { - let mut best_this_combination = vec![]; let mut primes_to_check = all_primes.clone(); + while let Some(first) = primes_to_check.pop() { let mut primes_matching_pattern = vec![]; + let digits = first.to_digits(); for digit in DIGITS { - let could_be_prime = apply_transformation(&digits, digit, &pattern); + let could_be_prime = + replace_digits_according_to_pattern_with_digit(&digits, digit, &pattern); if primes_to_check.contains(&could_be_prime) || could_be_prime == first { primes_matching_pattern.push(could_be_prime); } } - if primes_matching_pattern.len() > 2 { - best_this_combination.push(primes_matching_pattern); + if primes_matching_pattern.len() == TARGET_LENGTH { + println!("{primes_matching_pattern:#?}"); + exit(0); } } - if !best_this_combination.is_empty() { - best_of_all_combinations.push(get_longest(best_this_combination)); - } } - println!("{:#?}", get_longest(best_of_all_combinations)); } -fn apply_transformation(prime_as_digits: &[u8], new_digit: u8, pattern: &[bool]) -> Int { +fn replace_digits_according_to_pattern_with_digit( + prime_as_digits: &[u8], + new_digit: u8, + pattern: &[bool], +) -> Int { debug_assert_eq!(prime_as_digits.len(), pattern.len()); let mut multiplier = 1; let result = prime_as_digits @@ -73,32 +79,31 @@ fn apply_transformation(prime_as_digits: &[u8], new_digit: u8, pattern: &[bool]) result } -fn get_longest(mut vec: Vec>) -> Vec { - assert!( - !vec.is_empty(), - "cannot get the longest element of an empty vector" - ); - vec.sort_by_key(|c| c.len()); - let length = vec.last().unwrap().len(); - vec.into_iter().find(|v| v.len() == length).unwrap() -} - trait ToDigits { fn to_digits(&self) -> Vec; } +#[allow(clippy::needless_range_loop)] impl ToDigits for Int { fn to_digits(&self) -> Vec { - self.to_string() - .chars() - .map(|x| x.to_digit(10).unwrap() as u8) - .collect() + let oom = (*self as f64).log10().floor() as i32; + let length = oom as usize + 1; + let mut var = *self; + let mut result = vec![0; length]; + for i in 0..length as usize { + let power = 10_f64.powi(oom - i as i32); + let digit = (var as f64 / power).floor(); + var -= (digit * power) as Int; + result[i] = digit as u8; + } + assert_eq!(var, 0); + result } } #[cfg(test)] mod test { - use crate::{apply_transformation, ToDigits}; + use crate::{replace_digits_according_to_pattern_with_digit, ToDigits}; #[test] fn test_num_to_digits() { @@ -112,8 +117,14 @@ mod test { let new_digit = 0; let pattern = [false, true, true, true, false, false]; assert_eq!( - apply_transformation(&prime_as_digits, new_digit, &pattern), + replace_digits_according_to_pattern_with_digit(&prime_as_digits, new_digit, &pattern), 500_021 ); } + + #[test] + fn test_to_digits() { + let num = 37871_u64; + assert_eq!(vec![3, 7, 8, 7, 1], num.to_digits()); + } }