add 95, 17
This commit is contained in:
@@ -10,5 +10,15 @@ fn bench_primes_between_10e5_and_10e6(c: &mut Criterion) {
|
||||
});
|
||||
}
|
||||
|
||||
criterion_group!(benches, bench_primes_between_10e5_and_10e6);
|
||||
fn bench_primes_between_10_and_10e6(c: &mut Criterion) {
|
||||
c.bench_function("primes 10 to 10e6", |b| {
|
||||
b.iter(|| Primes::get_between(10, 1_000_000))
|
||||
});
|
||||
}
|
||||
|
||||
criterion_group!(
|
||||
benches,
|
||||
bench_primes_between_10_and_10e6,
|
||||
bench_primes_between_10e5_and_10e6
|
||||
);
|
||||
criterion_main!(benches);
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
[package]
|
||||
name = "proper_divisors"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
#num = "0.4.3"
|
||||
|
||||
[dev-dependencies]
|
||||
rstest = "0.25.0"
|
||||
@@ -0,0 +1,82 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ProperDivisors {
|
||||
map: HashMap<usize, Vec<usize>>,
|
||||
pub min: usize,
|
||||
pub max: usize,
|
||||
}
|
||||
|
||||
impl ProperDivisors {
|
||||
pub fn get_between(smaller: usize, larger: usize) -> Self {
|
||||
let mut result = HashMap::new();
|
||||
|
||||
for number in smaller..=larger {
|
||||
let mut divisors = vec![1];
|
||||
|
||||
let limit = usize::isqrt(number);
|
||||
|
||||
for i in (2..=limit).rev() {
|
||||
if number % i == 0 {
|
||||
let div_1 = i;
|
||||
let div_2 = number / i;
|
||||
|
||||
divisors.push(div_1);
|
||||
|
||||
if div_1 != div_2 {
|
||||
divisors.push(div_2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
divisors.sort_unstable();
|
||||
result.insert(number, divisors);
|
||||
}
|
||||
|
||||
Self {
|
||||
map: result,
|
||||
min: smaller,
|
||||
max: larger,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get(&self, number: usize) -> &[usize] {
|
||||
self.map.get(&number).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use rstest::rstest;
|
||||
|
||||
use crate::ProperDivisors;
|
||||
|
||||
#[rstest]
|
||||
#[case(6, vec![1, 2, 3])]
|
||||
#[case(28, vec![1, 2, 4, 7, 14])]
|
||||
#[case(12_496, vec![1, 2, 4, 8, 11, 16, 22, 44, 71, 88, 142, 176, 284, 568, 781, 1136, 1562, 3124, 6248])]
|
||||
fn one_proper_divisor(#[case] input: usize, #[case] expected: Vec<usize>) {
|
||||
let pd = ProperDivisors::get_between(input, input + 1);
|
||||
|
||||
assert_eq!(pd.get(input), expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn all_proper_divisors() {
|
||||
let pd = ProperDivisors::get_between(6, 30);
|
||||
|
||||
assert_eq!(pd.get(6), &[1, 2, 3]);
|
||||
assert_eq!(pd.get(28), &[1, 2, 4, 7, 14]);
|
||||
|
||||
println!("{:?}", pd.get(8));
|
||||
|
||||
let pd = ProperDivisors::get_between(12_496, 12_497);
|
||||
assert_eq!(
|
||||
pd.get(12_496),
|
||||
&[
|
||||
1, 2, 4, 8, 11, 16, 22, 44, 71, 88, 142, 176, 284, 568, 781, 1136, 1562, 3124, 6248
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
[package]
|
||||
name = "euler17"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
|
||||
[dev-dependencies]
|
||||
rstest = "0.25.0"
|
||||
@@ -0,0 +1,110 @@
|
||||
fn main() {
|
||||
let result: usize = (1..=1000).map(convert_number).sum();
|
||||
println!("{result}");
|
||||
}
|
||||
|
||||
fn convert_number(number: usize) -> usize {
|
||||
if number == 1_000 {
|
||||
return 11;
|
||||
};
|
||||
|
||||
let mut sum = 0;
|
||||
|
||||
if has_hundreds_digits(number) {
|
||||
sum += convert_hundreds(number);
|
||||
}
|
||||
|
||||
if has_hundreds_digits(number) && has_tens_or_single_digits(number) {
|
||||
sum += 3; // "and"
|
||||
}
|
||||
|
||||
if has_tens_or_single_digits(number) {
|
||||
sum += convert_tens_and_single_digits(number);
|
||||
}
|
||||
|
||||
sum
|
||||
}
|
||||
|
||||
fn convert_tens_and_single_digits(number: usize) -> usize {
|
||||
let number = get_tens_and_single_digits(number);
|
||||
let mut result = match number {
|
||||
x if x < 10 => convert_digit_to_letters(x),
|
||||
10 => 3,
|
||||
11 => 6,
|
||||
12 => 6,
|
||||
13 => 8,
|
||||
14 => 8,
|
||||
15 => 7,
|
||||
16 => 7,
|
||||
17 => 9,
|
||||
18 => 8,
|
||||
19 => 8,
|
||||
x if x < 40 => 6, // twenty, thirty are all of length 6
|
||||
x if x < 70 => 5, // forty, fifty, sixty
|
||||
x if x < 80 => 7, // seventy
|
||||
x if x < 100 => 6, // eighty, ninety
|
||||
_ => panic!(),
|
||||
};
|
||||
|
||||
if number > 20 {
|
||||
result += convert_digit_to_letters(number % 10);
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
fn get_tens_and_single_digits(number: usize) -> usize {
|
||||
number % 100
|
||||
}
|
||||
|
||||
fn has_tens_or_single_digits(number: usize) -> bool {
|
||||
get_tens_and_single_digits(number) > 0
|
||||
}
|
||||
|
||||
fn convert_hundreds(number: usize) -> usize {
|
||||
let hundreds = get_hundreds(number);
|
||||
let letters = convert_digit_to_letters(hundreds);
|
||||
letters + 7
|
||||
}
|
||||
|
||||
fn convert_digit_to_letters(number: usize) -> usize {
|
||||
match number {
|
||||
0 => 0,
|
||||
1 => 3,
|
||||
2 => 3,
|
||||
3 => 5,
|
||||
4 => 4,
|
||||
5 => 4,
|
||||
6 => 3,
|
||||
7 => 5,
|
||||
8 => 5,
|
||||
9 => 4,
|
||||
_ => unreachable!("should not happen if code is correct"),
|
||||
}
|
||||
}
|
||||
|
||||
fn has_hundreds_digits(number: usize) -> bool {
|
||||
get_hundreds(number) > 0
|
||||
}
|
||||
|
||||
fn get_hundreds(number: usize) -> usize {
|
||||
number / 100
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use rstest::rstest;
|
||||
|
||||
#[rstest]
|
||||
#[case(1, 5, 19)]
|
||||
#[case(115, 115, 20)]
|
||||
#[case(342, 342, 23)]
|
||||
#[case(1000, 1000, 11)]
|
||||
fn chain(#[case] min: usize, #[case] max: usize, #[case] expected: usize) {
|
||||
use crate::convert_number;
|
||||
|
||||
let sum: usize = (min..=max).map(convert_number).sum();
|
||||
assert_eq!(sum, expected);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "euler95"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
edition = "2024"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
@@ -10,4 +10,7 @@ rstest = "0.17"
|
||||
|
||||
[profile.release]
|
||||
debug = true
|
||||
lto = "fat"
|
||||
lto = "off"
|
||||
|
||||
[dependencies]
|
||||
proper_divisors = { version = "*", path = "../../lib/proper_divisors" }
|
||||
|
||||
+102
-74
@@ -1,118 +1,146 @@
|
||||
use std::collections::HashSet;
|
||||
use proper_divisors::ProperDivisors;
|
||||
use std::collections::HashMap;
|
||||
|
||||
const MIN: usize = 2;
|
||||
const MAX: usize = 1_000_000;
|
||||
|
||||
fn main() {
|
||||
let mut chains = vec![];
|
||||
let proper_divisors_map = ProperDivisors::get_between(MIN, MAX);
|
||||
let mut number_divisor_sum_map = NumberDivisorSumMap::build(proper_divisors_map);
|
||||
|
||||
let mut part_of_any_chain = HashSet::new();
|
||||
let mut longest_chain = vec![];
|
||||
|
||||
for current in 1..MAX {
|
||||
if part_of_any_chain.contains(¤t) {
|
||||
for number in MIN..MAX {
|
||||
if *number_divisor_sum_map.get(&number).unwrap_or(&1) == 1 {
|
||||
// if equals 1, then it's prime and useless
|
||||
// if it's `None`, it was already used
|
||||
continue;
|
||||
}
|
||||
try_build_chain_from_number(MAX, current, &mut chains, &mut part_of_any_chain);
|
||||
if let Some(chain) = try_build_chain_from_number(number, &mut number_divisor_sum_map) {
|
||||
dbg!(&chain, &longest_chain);
|
||||
if chain.len() > longest_chain.len() {
|
||||
longest_chain = chain;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
chains.sort_by_key(|chain| chain.len());
|
||||
dbg!(&longest_chain);
|
||||
|
||||
let longest = chains.last().unwrap();
|
||||
|
||||
let smallest = longest.iter().min().unwrap().to_owned();
|
||||
let smallest = longest_chain.iter().min().unwrap().to_owned();
|
||||
|
||||
println!("{smallest}");
|
||||
}
|
||||
|
||||
fn build_proper_divisors(max: usize) -> Vec<Vec<usize>> {
|
||||
todo!()
|
||||
#[derive(Debug)]
|
||||
struct NumberDivisorSumMap {
|
||||
map: HashMap<usize, usize>,
|
||||
max: usize,
|
||||
}
|
||||
|
||||
impl NumberDivisorSumMap {
|
||||
fn build(pd: ProperDivisors) -> Self {
|
||||
let mut number_divisor_sum_map = HashMap::new();
|
||||
|
||||
for number in pd.min..=pd.max {
|
||||
let sum: usize = pd.get(number).iter().sum();
|
||||
number_divisor_sum_map.insert(number, sum);
|
||||
}
|
||||
Self {
|
||||
map: number_divisor_sum_map,
|
||||
max: pd.max,
|
||||
}
|
||||
}
|
||||
|
||||
fn get(&self, key: &usize) -> Option<&usize> {
|
||||
self.map.get(key)
|
||||
}
|
||||
|
||||
fn remove(&mut self, key: &usize) {
|
||||
self.map.remove(key);
|
||||
}
|
||||
|
||||
fn remove_all(&mut self, keys: &[usize]) {
|
||||
for key in keys {
|
||||
self.remove(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn try_build_chain_from_number(
|
||||
max: usize,
|
||||
mut current: usize,
|
||||
chains: &mut Vec<Vec<usize>>,
|
||||
part_of_any_chain: &mut HashSet<usize>,
|
||||
) {
|
||||
mut number: usize,
|
||||
number_divisor_sum_map: &mut NumberDivisorSumMap,
|
||||
) -> Option<Vec<usize>> {
|
||||
let mut maybe_chain = vec![];
|
||||
|
||||
let mut debug = false;
|
||||
if number == 1064 {
|
||||
debug = true;
|
||||
}
|
||||
|
||||
loop {
|
||||
maybe_chain.push(current);
|
||||
if debug {
|
||||
dbg!(number);
|
||||
dbg!(&maybe_chain);
|
||||
}
|
||||
maybe_chain.push(number);
|
||||
|
||||
let next: usize = get_proper_divisors(current).into_iter().sum();
|
||||
let next: usize = match number_divisor_sum_map.get(&number) {
|
||||
Some(number) => *number,
|
||||
None => break None,
|
||||
};
|
||||
|
||||
if next > max || next == 0 {
|
||||
break;
|
||||
if next > number_divisor_sum_map.max || next == 1 || next == number {
|
||||
number_divisor_sum_map.remove_all(&maybe_chain);
|
||||
break None;
|
||||
}
|
||||
|
||||
if maybe_chain.contains(&next) {
|
||||
if maybe_chain.len() > 1 && *maybe_chain.first().unwrap() == next {
|
||||
for number in &maybe_chain {
|
||||
part_of_any_chain.insert(*number);
|
||||
}
|
||||
if maybe_chain.contains(&next) && maybe_chain.len() > 1
|
||||
//&& *maybe_chain.first().unwrap() == next
|
||||
{
|
||||
println!("{}", maybe_chain.first().unwrap());
|
||||
chains.push(maybe_chain);
|
||||
}
|
||||
break;
|
||||
|
||||
number_divisor_sum_map.remove_all(&maybe_chain);
|
||||
break Some(maybe_chain);
|
||||
}
|
||||
|
||||
current = next;
|
||||
number = next;
|
||||
}
|
||||
}
|
||||
|
||||
fn get_proper_divisors(x: usize) -> Vec<usize> {
|
||||
let mut result = vec![1];
|
||||
|
||||
let limit = x / 2 + 1;
|
||||
|
||||
for i in 2..limit {
|
||||
if result.contains(&i) {
|
||||
break;
|
||||
}
|
||||
|
||||
if x % i == 0 {
|
||||
let div_1 = i;
|
||||
let div_2 = x / i;
|
||||
result.push(div_1);
|
||||
|
||||
if div_2 != div_1 {
|
||||
result.push(div_2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result.sort_unstable();
|
||||
result
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use rstest::rstest;
|
||||
|
||||
#[rstest]
|
||||
#[case(6, vec![1, 2, 3])]
|
||||
#[case(28, vec![1, 2, 4, 7, 14])]
|
||||
#[case(12_496, vec![1, 2, 4, 8, 11, 16, 22, 44, 71, 88, 142, 176, 284, 568, 781, 1136, 1562, 3124, 6248])]
|
||||
fn proper_divisor(#[case] input: usize, #[case] expected: Vec<usize>) {
|
||||
use crate::get_proper_divisors;
|
||||
|
||||
assert_eq!(get_proper_divisors(input), expected);
|
||||
}
|
||||
use crate::{NumberDivisorSumMap, try_build_chain_from_number};
|
||||
use proper_divisors::ProperDivisors;
|
||||
|
||||
#[rstest]
|
||||
#[case(220, vec![vec![220, 284]])]
|
||||
#[case(12_496, vec![vec![12_496, 14_288, 15_472, 14_536, 14_264]])]
|
||||
fn chain(#[case] input: usize, #[case] expected: Vec<Vec<usize>>) {
|
||||
use std::collections::HashSet;
|
||||
#[case(220, vec![220, 284])]
|
||||
#[case(12_496, vec![12_496, 14_288, 15_472, 14_536, 14_264])]
|
||||
fn chain(#[case] input: usize, #[case] expected: Vec<usize>) {
|
||||
let larger = expected.iter().max().unwrap().to_owned() + 1;
|
||||
|
||||
use crate::try_build_chain_from_number;
|
||||
let pd = ProperDivisors::get_between(2, larger);
|
||||
let mut number_divisor_sum_map = NumberDivisorSumMap::build(pd);
|
||||
|
||||
let max = expected.iter().flatten().max().unwrap().to_owned();
|
||||
let mut part_of_any_chain = HashSet::new();
|
||||
let chain = try_build_chain_from_number(input, &mut number_divisor_sum_map).unwrap();
|
||||
|
||||
let mut chains = vec![];
|
||||
try_build_chain_from_number(max, input, &mut chains, &mut part_of_any_chain);
|
||||
assert_eq!(chain, expected);
|
||||
}
|
||||
|
||||
assert_eq!(chains, expected);
|
||||
#[test]
|
||||
fn all_chains() {
|
||||
let smaller = 2;
|
||||
let larger = 16_000;
|
||||
|
||||
let pd = ProperDivisors::get_between(smaller, larger);
|
||||
let mut number_divisor_sum_map = NumberDivisorSumMap::build(pd);
|
||||
|
||||
let chain = try_build_chain_from_number(220, &mut number_divisor_sum_map).unwrap();
|
||||
assert_eq!(chain, vec![220, 284]);
|
||||
|
||||
let chain = try_build_chain_from_number(12_496, &mut number_divisor_sum_map).unwrap();
|
||||
assert_eq!(chain, vec![12_496, 14_288, 15_472, 14_536, 14_264]);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user