说明
如果你在写这个程序的时候,发现你在IDE上运行结果完全正确,而在网站上总是Wrong Answer,恭喜你,这将让你倍涨经验(起码我找了很久才发现这个问题)
字典是存放顺序与你输入的顺序是不一样的!!!迭代读取的时候一定要小心!!!!!
下面讲下经过。。。
描述
罗马数字包含以下七种字符: I, V, X, L,C,D 和 M。
字符 数值
I 1
V 5
X 10
L 50
C 100
D 500
M 1000
例如, 罗马数字 2 写做 II ,即为两个并列的 1。12 写做 XII ,即为 X + II 。 27 写做 XXVII, 即为 XX + V + II 。
通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做 IIII,而是 IV。数字 1 在数字 5 的左边,所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地,数字 9 表示为 IX。这个特殊的规则只适用于以下六种情况:
I 可以放在 V (5) 和 X (10) 的左边,来表示 4 和 9。
X 可以放在 L (50) 和 C (100) 的左边,来表示 40 和 90。
C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900。
给定一个整数,将其转为罗马数字。输入确保在 1 到 3999 的范围内。
示例1:
输入: 3
输出: "III"
示例2:
输入: 4
输出: "IV"
示例3:
输入: 9
输出: "IX"
示例4:
输入: 58
输出: "LVIII"
解释: C = 100, L = 50, XXX = 30, III = 3.
示例5:
输入: 58
输出: "LVIII"
解释: C = 100, L = 50, XXX = 30, III = 3.
思路
乍一看,什么放左边放右边,有点凌乱的感jio,我们不妨把所有罗马数字的“基数”都给它罗列出来(当然是用字典了),一共有以下这些“基数”。
这里的字典一定要按照基数值从大到小的顺序排列 ,就好比我们从高位到低位写一个数字,总是从高位写到低位。
dict_roma = {
3000: 'MMM',
2000: 'MM',
1000: 'M',
900: 'CM',
500: 'D',
400: 'CD',
300: 'CCC',
200: 'CC',
100: 'C',
90: 'XC',
50: 'L',
40: 'IL',
30: 'XXX',
20: 'XX',
10: 'X',
9: 'IX',
5: 'V',
4: 'IV',
3: 'III',
2: 'II',
1: 'I',
}
然后再逐个去除基数,看有没有商(够不够除),一旦够除,商肯定也只能是1,这里用到了defaultdict(int)
这个标准库中的字典,方便统计数量。
最后再根据统计的情况生成最终结果字符串即可。
Code
from collections import defaultdict
class Solution:
def intToRoman(self, num):
"""
:type num: int
:rtype: str
"""
# 这里的预定义字典一定要从数值大道数值小排列
dict_roma = {
3000: 'MMM',
2000: 'MM',
1000: 'M',
900: 'CM',
500: 'D',
400: 'CD',
300: 'CCC',
200: 'CC',
100: 'C',
90: 'XC',
50: 'L',
40: 'IL',
30: 'XXX',
20: 'XX',
10: 'X',
9: 'IX',
5: 'V',
4: 'IV',
3: 'III',
2: 'II',
1: 'I',
}
num_dict = defaultdict(int)
for key in dict_roma.keys():
if int(num / key) != 0:
num_dict[key] += 1
num -= key
# 查找完了,提前退出,后面的key无需再试探
if num == 0:
break
result = ""
for key, value in num_dict.items():
if value != 0:
result += dict_roma[key]
return result
s = Solution()
print(s.intToRoman(4))
疑问
我在pycharm中运行程序,完全没问题,输入4时,输出为IV
可是在LeetCode跑起来,就是说我输入4的时候输出错误
我也是醉了,不知道是哪里的问题,真的想了很久很久。于是乎,我又遇到了
罗马数字转整数这个题,也出现了类似的错误,百度了一下,并没有找到什么相关答案。我灵机一动,是不是和字典的“无序性”有关?呵呵。。果然是这样
修改
上面说道,我用了defaultdict
这个工具,实验证明,它也是无序的。于是我干脆自己统计好了(省去defaultdict提供的便利),用了两个OrderedDict()
,关于OrderedDict()
大家自行百度,我这里说明一下它的一个特别之处。
一般字典取value,我们肯定是dictionary[key]
这样,但是在OrderedDict()
中,dictionary[key]
返回的是一个元组,所以取出具体值需要这样操作——
dictionary[key][0]
,ok,代码如下:
from collections import defaultdict
from collections import OrderedDict
class Solution:
def intToRoman(self, num):
"""
:type num: int
:rtype: str
"""
# 这里的预定义字典一定要从数值大道数值小排列
dict_roma = OrderedDict()
dict_roma['3000'] = 'MMM',
dict_roma['2000'] = 'MM',
dict_roma['1000'] = 'M',
dict_roma['900'] = 'CM',
dict_roma['500'] = 'D',
dict_roma['400'] = 'CD',
dict_roma['300'] = 'CCC',
dict_roma['200'] = 'CC',
dict_roma['100'] = 'C',
dict_roma['90'] = 'XC',
dict_roma['50'] = 'L',
dict_roma['40'] = 'XL',
dict_roma['30'] = 'XXX',
dict_roma['20'] = 'XX',
dict_roma['10'] = 'X',
dict_roma['9'] = 'IX',
dict_roma['5'] = 'V',
dict_roma['4'] = 'IV',
dict_roma['3'] = 'III',
dict_roma['2'] = 'II',
dict_roma['1'] = 'I'
num_dict = OrderedDict()
for key in dict_roma.keys():
if int(num / int(key)) != 0:
# 如果计数字典中存在这个键
if key in num_dict:
num_dict[key] += 1
else:
num_dict[key] = 1
num -= int(key)
# 查找完了,提前退出,a后面的key无需再试探
if num == 0:
break
result = ""
for key, value in num_dict.items():
if value != 0:
result += dict_roma[key][0]
return result
另:罗马数字转整数,思路几乎一样,就是预定义字典的顺序改变一下。
from collections import OrderedDict
class Solution:
def romanToInt(self, s):
"""
:type s: str
:rtype: int
"""
# 这里的预定义字典一定要从数值大道数值小排列
dict_roma = OrderedDict()
dict_roma['CM'] = 900,
dict_roma['CD'] = 400,
dict_roma['XC'] = 90,
dict_roma['XL'] = 40,
dict_roma['IX'] = 9,
dict_roma['IV'] = 4,
dict_roma['MMM'] = 3000,
dict_roma['MM'] = 2000,
dict_roma['M'] = 1000,
dict_roma['D'] = 500,
dict_roma['CCC'] = 300,
dict_roma['CC'] = 200,
dict_roma['C'] = 100,
dict_roma['L'] = 50,
dict_roma['XXX'] = 30,
dict_roma['XX'] = 20,
dict_roma['X'] = 10,
dict_roma['V'] = 5,
dict_roma['III'] = 3,
dict_roma['II'] = 2,
dict_roma['I'] = 1,
base_list = list(dict_roma.keys())
result = 0
for item in base_list:
try:
base_index = s.index(item)
num = dict_roma[item][0]
result += num
# 如果从头匹配到
if base_index == 0:
s = s[len(item) + base_index:]
# 如果在中间匹配到
else:
s = s[:base_index] + s[len(item) + base_index:]
except ValueError as e:
continue
return result