轨道
/
Scala
Scala
/
练习
/
罗马数字
罗马数字

罗马数字

中等

简介

如今,世界上大多数人都在使用阿拉伯数字(0–9)。 但如果你回到两千年前,就会发现大多数欧洲人用的其实是罗马数字。

写罗马数字时,我们会用到下面这些拉丁字母,每个字母都对应一个数值:

M D C L X V I
1000 500 100 50 10 5 1

一个罗马数字就是这些字母组成的一个序列,它的值就是所有字母数值的总和。 例如,XVIII 的值是 18(10 + 5 + 1 + 1 + 1 = 18)。

不过有一条规则会让事情变得复杂一些:同一个字母不能连续出现超过三次。 也就是说,我们不能用看起来很自然的 IIII 来表示 4 这样的数字。 对于这类数字,我们要用两个字母相减的方式来表示。 所以我们不把 4 看成 1 + 1 + 1 + 1,而是看成 5 - 1。 用我们现代的思维来看,有点费解的是:我们要把较小的数字写在前面。 这种情况只适用于以下几例:4(IV)、9(IX)、40(XL)、90(XC)、400(CD)和 900(CM)。

罗马数字里,顺序很重要! 字母(以及上面这些特殊的组合)必须按数值从大到小、从左到右排列。

下面是一些例子:

 105 => CV
---- => --
 100 => C
+  5 =>  V
 106 => CVI
---- => --
 100 => C
+  5 =>  V
+  1 =>   I
 104 => CIV
---- => ---
 100 => C
+  4 =>  IV

最后再来看一个更复杂的例子:

 1996 => MCMXCVI
----- => -------
 1000 => M
+ 900 =>  CM
+  90 =>    XC
+   5 =>      V
+   1 =>       I

说明

你的任务是把阿拉伯数字转换成罗马数字。

在本次练习中,我们只讨论传统的罗马数字,其中最大的数字是 MMMCMXCIX(即 3,999)。

Note

在阿拉伯数字和罗马数字之间进行转换的方法有很多种。 我们建议你先采用一种朴素的方法,熟悉罗马数字的概念,然后再去寻找更高效的方法。

别忘了在最后观看我们的深度探索视频,了解你可以采用的不同方法!

本 Track 专属说明

如果你想尝试点不一样的,也可以试试用unfold函数写一个解法。 你可能已经熟悉foldLeft/Right:把一个集合“映射”成其他东西(通常不是集合)。 unfoldLeft/Right则是“反向”操作:把某个东西(通常不是集合)“映射”成集合。 所以unfold是函数式编程标准技能库中顺理成章的补充,也是其中的一部分。

这道练习可以看作适合unfold的一个场景:把一个Int“映射”成一个String(当然,它隐式地就是一个Seq[Char])。

可惜,Scala 的集合库并没有包含unfoldLeft/Right。 不过,你可以从这里获取实现。

通过 GitHub 编辑 链接将在新窗口或新标签页中打开
Scala Exercism

准备好开始 罗马数字 了吗?

注册 Exercism,借助 95 个练习 和真人导师指导,学习并掌握 Scala,全部免费。

深入探索 罗马数字!

探索这个棘手练习的各种不同解法,从递归到基于表的查找,还有一种使用混合进制数的解法,以及 Common Lisp 的一些简单作弊手法。