13. 罗马数字转整数

这个题目特别长,I 代表 1 ,V 代表 5,X 代表 10 ,以此类推,输入一个罗马数字,怎么转换成整数,这里比较难处理的就是 4 和 9 ,40 和 90 …… 等的表达。

这道题,一看就有点让人不想动手做,其实没有丝毫难点,但是很繁琐和琐碎。但是,考虑到自己立下了一天写一道题的 flag,还是要写的,我想了一想,耐烦是冯唐说的成大事的必要素质,怕也是程序员的必要素质,耐烦,所以,就是很烦的代码,你要不要写?还是要的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
class Solution:
def romanToInt(self, s: str) -> int:
mapping = {'I':1, 'V': 5, 'X': 10, 'L': 50, 'C':100, 'D': 500, 'M': 1000}
i = 0
result = 0
l = len(s)
while i < l :
if s[i] == 'I' :
if i + 1 < l and s[i+1] == 'V' :
result += 4
i += 1
elif i + 1 < l and s[i+1] == 'X':
result += 9
i += 1
else:
result += 1

elif s[i] == 'X':
if i + 1 < l and s[i+1] == 'L':
result += 40
i += 1
elif i + 1 < l and s[i+1] == 'C':
result += 90
i += 1
else:
result += 10

elif s[i] == 'C':
if i + 1 < l and s[i+1] == 'D':
result += 400
i += 1
elif i + 1 < l and s[i+1] == 'M':
result += 900
i += 1
else:
result += 100
else:
result += mapping[s[i]]
i += 1
return result

我就写了上面的代码,果然极其乏味,我以此写对了,不用 mapping 也是可以的,用了也没节省很多。从中,我学到了一个点,就是 Python 是没有 switch 语句的,只能用 if 来代替,那也没什么。

然后我还是看了看评论和题解,果然,就是这么无聊的题目,有人也能给你写出一朵花来:

1
2
3
4
class Solution:
def romanToInt(self, s: str) -> int:
d = {'I':1, 'IV':3, 'V':5, 'IX':8, 'X':10, 'XL':30, 'L':50, 'XC':80, 'C':100, 'CD':300, 'D':500, 'CM':800, 'M':1000}
return sum(d.get(s[max(i-1, 0):i+1], d[n]) for i, n in enumerate(s))

来赏析一个老哥的作品,Python,两行搞定。简直了。同样是使用 dict 数据结构做了个映射,看看这个老哥的功力,对 api 熟悉到了一定的境界,让我叹为观止。这里用到了 dict 的一个 api,get 方法,这个方法允许输入第二个参数,参数的作用是一旦没有取到,就用第二个参数作为缺省值来返回。老哥利用了这一点,每次迭代都尝试从串里取两位出来,如果取到了合法值,就查表取得数值,如果没有取到合法值,就用第二个位的字母的值代替,真是巧妙,省掉了多少个 if 条件啊,妙,实在是妙!

再看 max 函数的用法,迭代的过程中,每次需要取两个出来,但是第一个字符的时候,只能取一个,用了一个 max,当下标为负数的时候,就只取一位数字,又是妙到颠毫。还展示了一个 enumerate 方法迭代 dict 的用法,就相对来说比较平淡了。

熟练到一定境界,写的代码就比我短 20 倍。可见,编写代码是一种技艺, 是可以无限锤炼的。