# 用欧拉计划学Rust语言（第17~21题）

## 第17题

1到1000用英文单词写下来，求总字符个数（空格和连字符不算），例如：342，英文单词是：three hundred and forty-two。

• 数字转换成英文单词
• 1到19的拼写
• 20到99的拼写
• 100到999的拼写
• 1000的拼写
• 单词中去掉空格和连字符
• 取字符总数

1到19的拼写比较特殊，需要分别对待，而超过20的数，可以利用递归调用。这里可以学到String的语法知识点。Rust中的字符串有点烦人，list[n].to_string()、"one thousand".to_string()的这种写法让人非常不适应。除了String之外，还有字符串切片(slice)、字符常量，需要看基础教程慢慢理解。

fn english_number(n: usize) -> String {
let list0_9 = vec![
"zero", "one", "two", "three", "four",
"five", "six", "seven", "eight", "nine",
];
if n <= 9 {
return list0_9[n].to_string();
}
if n <= 19 {
let list = vec![
"ten", "eleven", "twelve", "thirteen", "fourteen",
"fifteen", "sixteen", "seventeen", "eighteen", "nineteen",
];
return list[n - 10].to_string();
}
if n <= 99 {
let a: usize = n / 10; // 十位
let b: usize = n % 10;
let list = vec![
"", "", "twenty", "thirty", "forty",
"fifty", "sixty", "seventy", "eighty", "ninety"
];
let str = list[a].to_string();
if b > 0 {
return str + "-" + &english_number(b);
}
return str;
}
if n <= 999 {
let a: usize = n / 100; // 百位
let b: usize = n % 100;
let str = list0_9[a].to_string() + " hundred";
if b > 0 {
return str + " and " + &english_number(b);
}
return str;
}
if n == 1000 {
return "one thousand".to_string();
}
return "unknown".to_string();
}


fn remove_space(s: &str) -> String {
s.chars().filter(|c| *c != ' ' && *c != '-').collect()
}



let mut sum = 0;
for n in 1..=1000 {
let s = remove_space(&english_number(n));
sum += s.len();
// println!("{}: {} {}", n, english_number(n), s.len());
}
println!("{}", sum);


## 第18题

let w = [
75, // row 1
95, 64,  // row 2
17, 47, 82,  // row 3
18, 35, 87, 10,
20, 04, 82, 47, 65,
19, 01, 23, 75, 03, 34,
88, 02, 77, 73, 07, 63, 67,
99, 65, 04, 28, 06, 16, 70, 92,
41, 41, 26, 56, 83, 40, 80, 70, 33,
41, 48, 72, 33, 47, 32, 37, 16, 94, 29,
53, 71, 44, 65, 25, 43, 91, 52, 97, 51, 14,
70, 11, 33, 28, 77, 73, 17, 78, 39, 68, 17, 57,
91, 71, 52, 38, 17, 14, 91, 43, 58, 50, 27, 29, 48,
63, 66, 04, 68, 89, 53, 67, 30, 73, 16, 69, 87, 40, 31,
04, 62, 98, 27, 23, 09, 70, 98, 73, 93, 38, 53, 60, 04, 23,
];


fn row(n: usize) -> usize {
let mut s = 0;
for r in 1.. {
s += r;
if s > n {return r;}
}
return 0;
}


fn max_path_weight(w: &[u32], n: usize) -> u32 {
if n >= w.len() {return 0;} //越界判断
let r = row(n);
let bottom_row = row(w.len() - 1);
if r == bottom_row { // 递归的退出条件
return w[n];
}
let left = max_path_weight(w, n + r);
let right = max_path_weight(w, n + r + 1);
let max = if left > right {left} else {right};
return w[n] + max;
}


println!("{}", max_path_weight(&w, 0));


## 第19题

use chrono::prelude::*;
use time::Duration;


let mut count = 0;
let mut d = Utc.ymd(1901, 1, 1);
while d <= Utc.ymd(2000, 12, 31) {
if d.weekday() == Weekday::Sun && d.day() == 1 {
println!("{}", d);
count += 1;
}
d = d + Duration::days(1);
}
println!("{}", count);


## 第20题

let mut prod = BigUint::from(1 as u64);
for i in 1..=100 {
prod *= BigUint::from(i as u64);
}

let s = full_str
.chars()
.map(|c| c.to_digit(10).unwrap())
.sum::<u32>();
println!("{}", s);


## 第21题

10000之内的所有亲和数之和。所谓亲和数，是指两个正整数中，彼此的全部约数之和（本身除外）与另一方相等。比如，220的因子有1, 2, 4, 5, 10, 11, 20, 22, 44, 55 和 110，因子之和是 284，而284的所有因子是 1, 2, 4, 71 和 142，因子之和是220。

• 求所有因子
• 因子求和
• 找出亲和数
• 亲和数再求和

fn half_factors(num: u32) -> Vec<u32> {
let s = (num as f32).sqrt() as u32;
(1..=s).filter(|x| num % x == 0).collect::<Vec<u32>>()
}


fn proper_divisors(num: u32) -> Vec<u32> {
let mut v = half_factors(num);
for i in (1..v.len()).rev() { //不要num自身，所以从1开始
v.push(num / v[i]);
}
v
}


fn proper_divisors_sum(num: u32) -> u32 {
let divs = proper_divisors(num);
divs.iter().sum::<u32>()
}


let mut sum = 0;
for a in 1u32..10000 {
let b = proper_divisors_sum(a);
if a != b && proper_divisors_sum(b) == a {
sum += a;
println!("{} {}", a, b);
}
}
println!("{}", sum);


1539870_KBNiIXymh4SnmDEDZmUTg7tu1MTBVlLj

----==== Email: slofslb (GTD) qq.com 请将(GTD)换成@ ====----

---- 魔方桥牌象棋、游戏人生...