haskell 基础理解(41)

罗马数字

【题目】古罗马的数字表示体系特点之一是繁难。具说是因为宗教的原因不能在数字中使用“零”的概念。这种体系如今仍有少量使用。比如书籍的目录页,时钟的刻度等。
千级以内的表示法是这样的。一些固定的字母代表固定的数字:
I(1)V(5)X(10)L(50)C(100)D(500)M(1000)
然后,用它们的重复表达更大的数。1,2,3,4… 表示为:
I, II, III, IV, V, VI, VII, VIII, IX, X, XI, XII, XIII, XIV, XV …
规律是:每个字母最多能重复3次。那如何表达4,9 呢? 分别为 5-1, 10-1, 就是说: I X C 这3个字母可以放在比它大的单位的左边,意思是从大单位中减去这个值。
实战一下:
CMLXXXIV 表示:984
CCCXCVI 表示: 396
请编程,从一个罗马数字串转换为十进制数字的形式。

一眼看上去,就是把每个罗马数字符号转成对应的真值,加起来就差不多了。
麻烦的是:4,9,40,90 …这些另类,怎样准确识别出来并恰当处理。

先上haskell代码:

romanNum :: String -> Int
romanNum s = sum $ map f值 s ++ zipWith f补 s (tail s)
    where
    f值 'I' = 1
    f值 'V' = 5
    f值 'X' = 10
    f值 'L' = 50
    f值 'C' = 100
    f值 'D' = 500
    f值 'M' = 1000
    f值 _ = error "bad roman number"
    f补 'I' 'V' = -2
    f补 'I' 'X' = -2
    f补 'X' 'L' = -20
    f补 'X' 'C' = -20
    f补 'C' 'D' = -200
    f补 'C' 'M' = -200
    f补  _ _ = 0

main :: IO ()
main = do
    print $ romanNum "CMLXXXIV"
    print $ romanNum "CCCXCVI"

看起来好像出奇地简单。因为它用了枚举法。
就是把所有的特殊情况都逐一列举出来,分别进行订正。
所有字母都按原值加起来。对于特殊的情况再把多加的给退回来即可。

其实,特殊的情况很少,只有: 4, 9, 40, 90, 400, 900
这么少的情况,没有必要找出一个普遍适用的“规律”来,那样代码反而难懂且容易出现漏洞。

枚举法可以说是程序设计中最为朴素、最为可靠的方法。只要能用它就应该优先选它。除非遇到了其它约束的限制。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值