1. 程式人生 > >LeetCode(12&13)—— 整數與羅馬數字相互轉化

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