LeetCode(12&13)—— 整數與羅馬數字相互轉化
說明
如果你在寫這個程式的時候,發現你在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