Roman to Integer [LeetCode 13]
1- 问题描述
Given a roman numeral, convert it to an integer.
Input is guaranteed to be within the range from 1 to 3999.
2- 罗马数字[1]
罗马数字共有7个,即I(1)、V(5)、X(10)、L(50)、C(100)、D(500)和M(1000)。按照下述的规则可以表示任意正整数。需要注意的是罗马数字中没有“0”,与进位制无关。一般认为罗马数字只用来记数,而不作演算。
- 重复数次:一个罗马数字重复几次,就表示这个数的几倍。
- 右加左减:
- 在较大的罗马数字的右边记上较小的罗马数字,表示大数字加小数字。
- 在较大的罗马数字的左边记上较小的罗马数字,表示大数字减小数字。
- 左减的数字有限制,仅限于I、X、C。比如45不可以写成VL,只能是XLV
- 但是,左减时不可跨越一个位数。比如,99不可以用IC()表示,而是用XCIX()表示。(等同于阿拉伯数字每位数字分别表示。)
- 左减数字必须为一位,比如8写成VIII,而非IIX。
- 右加数字不可连续超过三位,比如14写成XIV,而非XIIII。(见下方“数码限制”一项。)
- 加线乘千:
- 在罗马数字的上方加上一条横线或者加上下标的Ⅿ,表示将这个数乘以1000,即是原数的1000倍。
- 同理,如果上方有两条横线,即是原数的1000000()倍。
数码限制:
- 同一数码最多只能出现三次,如40不可表示为XXXX,而要表示为XL。
- 例外:由于IV是古罗马神话主神朱庇特(即IVPITER,古罗马字母里没有J和U)的首字,因此有时用IIII代替IV。
3- 思路分析
两种思路:从左向右、从右向左^_^
左 —> 右:从前向后遍历罗马数字,如果某个数比前一个数小,则加上该数。反之,减去前一个数的两倍然后加上该数。详见[2]
左 <— 右:如果当前数比前一位小,则减去该数,否则加上。
4- Python实现(从右往左遍历)
1 class Solution: 2 # @param {string} s 3 # @return {integer} 4 def romanToInt(self, s): 5 r2a = {'I':1, 'V':5, 'X':10, 'L':50, 'C':100, 'D':500, 'M':1000} 6 sList = list(s.strip()) 7 nList = map(lambda x: r2a[x], sList) 8 nList.reverse() 9 10 # 方法1 11 res = 0 12 last = 0 # 上一位数值(右一位) 13 for i in nList: 14 if last <= i: # 不小于上一位,加 15 res += i 16 else: # 小于上一位,减 17 res -= i 18 last = i 19 return res 20 21 ''' 22 # 方法2 23 s = [nList[0]] 24 for i in range(1, len(nList)): 25 if nList[i] >= nList[i-1]: 26 s.append(nList[i]) 27 else: 28 s.append(-nList[i]) 29 return sum(s) 30 31 32 # 方法3 33 digits = { "I":1, "V":5, "X":10, "L":50, "C":100, "D":500, "M":1000 } 34 len_s = len(s) 35 num = 0 36 for i in range(0, len_s - 1): 37 cur = digits[s[i]] 38 next = digits[s[i + 1]] 39 if cur >= next: 40 num += cur 41 else: 42 num -= cur 43 num += digits[s[len_s - 1]] 44 return num 45 ’‘’
[1] 罗马数字