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);
|
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]
|
[package]
|
||||||
name = "euler95"
|
name = "euler95"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2024"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# 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]
|
[profile.release]
|
||||||
debug = true
|
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;
|
const MAX: usize = 1_000_000;
|
||||||
|
|
||||||
fn main() {
|
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 {
|
for number in MIN..MAX {
|
||||||
if part_of_any_chain.contains(¤t) {
|
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;
|
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_chain.iter().min().unwrap().to_owned();
|
||||||
|
|
||||||
let smallest = longest.iter().min().unwrap().to_owned();
|
|
||||||
|
|
||||||
println!("{smallest}");
|
println!("{smallest}");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_proper_divisors(max: usize) -> Vec<Vec<usize>> {
|
#[derive(Debug)]
|
||||||
todo!()
|
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(
|
fn try_build_chain_from_number(
|
||||||
max: usize,
|
mut number: usize,
|
||||||
mut current: usize,
|
number_divisor_sum_map: &mut NumberDivisorSumMap,
|
||||||
chains: &mut Vec<Vec<usize>>,
|
) -> Option<Vec<usize>> {
|
||||||
part_of_any_chain: &mut HashSet<usize>,
|
|
||||||
) {
|
|
||||||
let mut maybe_chain = vec![];
|
let mut maybe_chain = vec![];
|
||||||
|
|
||||||
|
let mut debug = false;
|
||||||
|
if number == 1064 {
|
||||||
|
debug = true;
|
||||||
|
}
|
||||||
|
|
||||||
loop {
|
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 {
|
if next > number_divisor_sum_map.max || next == 1 || next == number {
|
||||||
break;
|
number_divisor_sum_map.remove_all(&maybe_chain);
|
||||||
|
break None;
|
||||||
}
|
}
|
||||||
|
|
||||||
if maybe_chain.contains(&next) {
|
if maybe_chain.contains(&next) && maybe_chain.len() > 1
|
||||||
if maybe_chain.len() > 1 && *maybe_chain.first().unwrap() == next {
|
//&& *maybe_chain.first().unwrap() == next
|
||||||
for number in &maybe_chain {
|
{
|
||||||
part_of_any_chain.insert(*number);
|
|
||||||
}
|
|
||||||
println!("{}", maybe_chain.first().unwrap());
|
println!("{}", maybe_chain.first().unwrap());
|
||||||
chains.push(maybe_chain);
|
|
||||||
}
|
number_divisor_sum_map.remove_all(&maybe_chain);
|
||||||
break;
|
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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use rstest::rstest;
|
use rstest::rstest;
|
||||||
|
|
||||||
#[rstest]
|
use crate::{NumberDivisorSumMap, try_build_chain_from_number};
|
||||||
#[case(6, vec![1, 2, 3])]
|
use proper_divisors::ProperDivisors;
|
||||||
#[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);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[case(220, vec![vec![220, 284]])]
|
#[case(220, vec![220, 284])]
|
||||||
#[case(12_496, vec![vec![12_496, 14_288, 15_472, 14_536, 14_264]])]
|
#[case(12_496, vec![12_496, 14_288, 15_472, 14_536, 14_264])]
|
||||||
fn chain(#[case] input: usize, #[case] expected: Vec<Vec<usize>>) {
|
fn chain(#[case] input: usize, #[case] expected: Vec<usize>) {
|
||||||
use std::collections::HashSet;
|
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 chain = try_build_chain_from_number(input, &mut number_divisor_sum_map).unwrap();
|
||||||
let mut part_of_any_chain = HashSet::new();
|
|
||||||
|
|
||||||
let mut chains = vec![];
|
assert_eq!(chain, expected);
|
||||||
try_build_chain_from_number(max, input, &mut chains, &mut part_of_any_chain);
|
}
|
||||||
|
|
||||||
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