当前位置: 首页 > 工具软件 > romannumerals > 使用案例 >

Rust: codewars的Roman Numerals Encoder

东方智敏
2023-12-01

算法很简单,其实就是输入一个阿拉伯数字,输出一个罗马数字。
说明:但是这个只是一个简单的版本,输入的数字不算大,不涉及相对较大数的复杂罗马数字表达(比如,上面带横线之类)。
比如:
1990 =>:1000=M, 900=CM, 90=XC; => MCMXC.
2008 => 2000=MM, 8=VIII; => MMVIII.
1666 => MDCLXVI.
1、一些提示
Symbol Value
I 1
V 5
X 10
L 50
C 100
D 500
M 1,000

2、同一个字符,最多可以重复3次。
3、40,400的可以分别用XL,CD来表达。
其它的说明,可以找度娘。

一、我的算法

fn num_as_roman(num: i32) -> String {
    let data: HashMap<i32, &str> = [(0, ""),
                                    (1, "I"),
                                    (2, "II"),
                                    (3, "III"),
                                    (4, "IV"),
                                    (5, "V"),
                                    (6, "VI"),
                                    (7, "VII"),
                                    (8, "VIII"),
                                    (9, "IX"),
                                    (10, "X"),
                                    (20, "XX"),
                                    (30, "XXX"),
                                    (40, "XL"),
                                    (50, "L"),
                                    (60, "LX"),
                                    (70, "LXX"),
                                    (80, "LXXX"),
                                    (90, "XC"),
                                    (100, "C"),
                                    (200, "CC"),
                                    (300, "CCC"),
                                    (400, "CD"),
                                    (500, "D"),
                                    (600, "DC"),
                                    (700, "DCC"),
                                    (800, "DCCC"),
                                    (900, "CM"),
                                    (1000, "M"),
                                    (2000, "MM"),
                                    (3000, "MMM")]
        .into_iter()
        .map(|w| (w.0, w.1))
        .collect::<HashMap<i32, &str>>();
    let chars: Vec<char> = num.to_string().chars().into_iter().map(|x| x).collect();
    let fact_nums = fact_num(num);
    fact_nums.into_iter()
        .map(|x| *(data.get(&(x.0 * x.1)).unwrap()))
        .collect::<Vec<&str>>()
        .join("")
}
fn fact_num(num: i32) -> Vec<(i32, i32)> {
    let len = num.to_string().len() as i32;
    let mut result: Vec<(i32, i32)> = Vec::new();
    let mut remain: i32 = num;
    for i in 0..len {
        let k = len - i - 1;
        let pow_value = 10_f64.powf(k as f64) as i32;
        let temp = remain / pow_value;
        remain = remain - temp * pow_value;
        if k < 1 {
            result.push((1, temp));
        } else {
            result.push((temp, pow_value));
        }
        println!("temp :{:?}, remain:{:?}", temp, remain);
    }
    result
}

当然,也可以用 HashMap

fn num_as_roman(num: i32) -> String {
    let data: HashMap<i32, String> = [(0, ""),
                                      (1, "I"),
                                      (2, "II"),
                                      (3, "III"),
                                      (4, "IV"),
                                      (5, "V"),
                                      (6, "VI"),
                                      (7, "VII"),
                                      (8, "VIII"),
                                      (9, "IX"),
                                      (10, "X"),
                                      (20, "XX"),
                                      (30, "XXX"),
                                      (40, "XL"),
                                      (50, "L"),
                                      (60, "LX"),
                                      (70, "LXX"),
                                      (80, "LXXX"),
                                      (90, "XC"),
                                      (100, "C"),
                                      (200, "CC"),
                                      (300, "CCC"),
                                      (400, "CD"),
                                      (500, "D"),
                                      (600, "DC"),
                                      (700, "DCC"),
                                      (800, "DCCC"),
                                      (900, "CM"),
                                      (1000, "M"),
                                      (2000, "MM"),
                                      (3000, "MMM")]
        .into_iter()
        .map(|w| (w.0, w.1.to_string()))
        .collect::<HashMap<i32, String>>();
    let chars: Vec<char> = num.to_string().chars().into_iter().map(|x| x).collect();
    let fact_nums = fact_num(num);
    fact_nums.into_iter()
        .map(|x| (&data).get(&(x.0 * x.1)).unwrap().to_string())
        .collect::<Vec<String>>()
        .join("")
}

二、精彩的算法

fn rep(c: char, n: usize) -> String {
  std::iter::repeat(c).take(n).collect()
}

fn roman(d: u8, p: usize) -> String {
  let nines = ["IX", "XC", "CM"];
  let fives = ["V", "L", "D"];
  let fours = ["IV", "XL", "CD"];
  let ones  = ['I', 'X', 'C', 'M'];
  match d {
    0 => String::from(""),
    9 => String::from(nines[p]),
    n if n > 5 => String::from(fives[p]) + &rep(ones[p], (n - 5) as usize),
    5 => String::from(fives[p]),
    4 => String::from(fours[p]),
    n => rep(ones[p], n as usize),
  }
}

fn num_as_roman(num: i32) -> String {
  let s = num.to_string();
  let l = s.len();
  let mut r = String::new();
  for (i, d) in s.chars().enumerate() {
    let p = (l - i - 1) as usize;
    r += &roman(d.to_digit(10).unwrap() as u8, p);
  }
  r
}

2、

const ONES: [&'static str; 10] = ["", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"];
const TENS: [&'static str; 10] = ["", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"];
const HUNS: [&'static str; 10] = ["", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"];
const TOUS: [&'static str; 10] = ["", "M", "MM", "MMM", "", "", "", "", "", ""];
const DIGITS: [[&'static str; 10]; 4] = [ONES, TENS, HUNS, TOUS];

fn num_as_roman(num: i32) -> String {
  [num/1000, num/100, num/10, num]
  .into_iter()
  .enumerate()
  .map(|(i, &d)| DIGITS[3 - i][(d % 10) as usize])
  .collect()
}

3、

static ROMAN_DEC: [(&'static str, i32); 13] = 
  [("M", 1000), ("CM", 900), ("D", 500), ("CD", 400),
   ("C",  100), ("XC",  90), ("L",  50), ("XL",  40),
   ("X",   10), ("IX",   9), ("V",   5), ("IV",   4),
   ("I",    1)];


/// Converts a number to a string representating roman numeral.
fn num_as_roman(num: i32) -> String {
  let mut num = num;
  let mut result = String::new();
  for &(ref lit, val) in &ROMAN_DEC {
    while num >= val {
      result.push_str(lit);
      num -= val;
    }
    if num == 0 { break }
  }
  result
}
 类似资料: