对一个罗马数字与阿拉伯数字转换算法的分析
2014-12-29 19:55
302 查看
title: 对一个罗马数字与阿拉伯数字转换算法的分析
date: 2014-12-29 18:34:30
categories: [算法]
tags: [算法,Python]
---
在看《Dive into Python》的单元测试时,发现用作例子的“阿拉伯数字-罗马数字”的转换算法非常的巧妙,现在发上来和大家分享一下。
这个算法的聪明之处,就在于他通过一个romanNumeralMap,把罗马数字与阿拉伯数字里面的“边界值”做出一一对应。这个边界刚刚好是罗马数字组合之间的转换。例如,I,II,III都可以通过第一个边界值组合获得;V,VI,VII,VIII可以通过V和I的组合获得。而对于一些特殊的值,则直接列出来。例如IV。通过这个边界值的组合,就能实现所需求的转换。这就类似于在一些机读卡上,需要填写1到100的数字,他会使用0,1,2,4,7这样以来:
首先看一下toRoman()函数,把阿拉伯数字转换成罗马数字。它使用Python连接字符串的操作符号 + 来使“边界值”连接到一起。例如用作例子的n = 1356,程序遍历romanNumeralMap,寻找n对应的罗马数字,如果找不到,那就找刚刚比n小一点的数字对应的罗马字符。遍历在能使n 在romanNumeralMap有对应值时结束。
所以1356对应的值为MCCCLVI。 这样的操作很类似于在十进制里面,一个数字1356 = 1000 + 300 + 50 + 6,只是阿拉伯数字里面6是一个单独的符号,而罗马数字里面VI是个V + I的组合而已。
下面再说说fromRoman()函数,把罗马数字转换成阿拉伯数字。这个函数在理解上面可能比toRoman()稍稍要困难一点。
还是用例子来说明,MCMLXXII转换成阿拉伯数字。
其中如下代码
作用是把字符串s中,从第index位到第index+ len(numeral)位(不包含第index + len(numeral)位自身)的字符提取出来。比如:
即s的第2,3,4位被取出。
回到对s = 'MCMLXXII'的处理。
所以MCMLXXII对于的阿拉伯数字是1000+900+50+10+10+1+1 = 1972
这个方法,把一个罗马数字从高位开始逐次剥离最高位,从而渐渐的把数字缩小。
最近正在学习算法。因为越来越发现现在做的东西,如果仅仅实现功能的话,性能会出现瓶颈。希望我以后能写出更好的算法。
date: 2014-12-29 18:34:30
categories: [算法]
tags: [算法,Python]
---
在看《Dive into Python》的单元测试时,发现用作例子的“阿拉伯数字-罗马数字”的转换算法非常的巧妙,现在发上来和大家分享一下。
romanNumeralMap = (('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)) def toRoman(n): result = "" for numeral, integer in romanNumeralMap: while n >= integer: result += numeral n -= integer return result def fromRoman(s): result = 0 index = 0 for numeral, integer in romanNumeralMap: while s[index:index+len(numeral)] == numeral: result += integer index += len(numeral) return result print toRoman(1356) print fromRoman('MCMLXXII')
这个算法的聪明之处,就在于他通过一个romanNumeralMap,把罗马数字与阿拉伯数字里面的“边界值”做出一一对应。这个边界刚刚好是罗马数字组合之间的转换。例如,I,II,III都可以通过第一个边界值组合获得;V,VI,VII,VIII可以通过V和I的组合获得。而对于一些特殊的值,则直接列出来。例如IV。通过这个边界值的组合,就能实现所需求的转换。这就类似于在一些机读卡上,需要填写1到100的数字,他会使用0,1,2,4,7这样以来:
3 = 1 + 2; 5 = 4 + 1; 6 = 4 + 2; 8 = 7 + 1; 9 = 7 + 2.
首先看一下toRoman()函数,把阿拉伯数字转换成罗马数字。它使用Python连接字符串的操作符号 + 来使“边界值”连接到一起。例如用作例子的n = 1356,程序遍历romanNumeralMap,寻找n对应的罗马数字,如果找不到,那就找刚刚比n小一点的数字对应的罗马字符。遍历在能使n 在romanNumeralMap有对应值时结束。
找到刚刚比1356小的那个值对应的罗马数字,也就是1000,M 再继续找刚刚比n = 1356 - 1000 = 356小的数,也就是100,C; 又继续找比n = 356 - 100 = 256小的数,还是100,也就是C; 再找比n = 256 - 100 = 156小的数,仍然是100,C; 继续找比n = 156 - 100 = 56 小的数,50,L; 继续找比n = 56 - 50 = 6小的数,5,V; 继续找n = 6 - 5 = 1对于的数,1,I。 结束。
所以1356对应的值为MCCCLVI。 这样的操作很类似于在十进制里面,一个数字1356 = 1000 + 300 + 50 + 6,只是阿拉伯数字里面6是一个单独的符号,而罗马数字里面VI是个V + I的组合而已。
下面再说说fromRoman()函数,把罗马数字转换成阿拉伯数字。这个函数在理解上面可能比toRoman()稍稍要困难一点。
还是用例子来说明,MCMLXXII转换成阿拉伯数字。
其中如下代码
s[index:index+len(numeral)]
作用是把字符串s中,从第index位到第index+ len(numeral)位(不包含第index + len(numeral)位自身)的字符提取出来。比如:
>>> a = 'helloworld' >>> print a[2:5] llo
即s的第2,3,4位被取出。
回到对s = 'MCMLXXII'的处理。
首先map中第一个罗马字符是M,只有一位,就把s 的第0位拿出来对比,发现s的第0位刚刚好是M,于是得到一个1000,index变为1,则之后从s的第一位开始。简单的说,相当于s 变成了s = 'CMLXXII' 接下来,经过一些无效的值以后,轮换到CM,发现CM为两位,就取出s的前两位,也就是CM,发现在s中刚刚好有CM,于是得到900. index再加2,则实际上s就相当于变成了LXXII 继续经过一些无效值以后,轮换到了L,发现s当前的1位为L,于是在map中有对应的值50.然后index加1,s相当于变成了XXII 接下来到了X,发现s当前的1位为X,在map中有对应的值10.然后index 再加1,s变成了XII 虽然这个时候人已经知道是12了,但是计算机还是不知道,于是继续一个X,s变为II 然后出现一个I,s变为I 终于程序找到了一个直接相等的值I,于是转换结束。
所以MCMLXXII对于的阿拉伯数字是1000+900+50+10+10+1+1 = 1972
这个方法,把一个罗马数字从高位开始逐次剥离最高位,从而渐渐的把数字缩小。
最近正在学习算法。因为越来越发现现在做的东西,如果仅仅实现功能的话,性能会出现瓶颈。希望我以后能写出更好的算法。
相关文章推荐
- 对一个罗马数字与阿拉伯数字转换算法的分析
- 一个将阿拉伯数字转换成中文大写的好算法(C#)
- 58. 分析、测试与总结:罗马数字和阿拉伯数字的转换[roman to integer and integer to roman in c++]
- 一个将阿拉伯数字转换成中文大写的最简单算法
- 分析、测试与总结:罗马数字和阿拉伯数字的转换[roman to integer and integer to roman in c++]
- 一个将阿拉伯数字转换成中文大写的最简单算法
- 一个将阿拉伯数字转换成中文大写的好算法【原创】(C#)
- 一个将阿拉伯数字转换成中文大写的算法[C#]
- 一个将阿拉伯数字转换成中文大写地好算法
- 把一个阿拉伯数字转换成中文数字的算法
- 将一个多项式的系数表示转换成点表示算法分析
- 将阿拉伯数字转换为罗马数字
- 一个比较简单的,只做了正数,一万位以内的,阿拉伯数字转换成大写数字的程序
- 一个将阿拉伯数字转换为中文数字近似读法的程序
- 阿拉伯数字转换成罗马数字(一)
- 一个将阿拉伯数字转换为中文数字近似读法的程序
- 经典题:罗马数字和阿拉伯数字的相互转换
- 将阿拉伯数组转换成为罗马数字
- 罗马数字转换阿拉伯数字(Java版,考虑较为全面)
- 阿拉伯数字转换成罗马数字(二)