1. 程式人生 > >LeetCode 整數轉羅馬數字

LeetCode 整數轉羅馬數字

題目:羅馬數字包含以下七種字元: I, V, X, LCD 和 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:

輸入: 58
輸出: "LVIII"
解釋: C = 100, L = 50, XXX = 30, III = 3.

示例 3:

輸入: 1994
輸出: "MCMXCIV"
解釋: M = 1000, CM = 900, XC = 90, IV = 4.

思路:定義兩個函式:函式一、將輸入的數字按每一位分解,如1994分解得到1000,900,90,4。函式二、先找到能表示輸入數字的最大基本符號,再用該數值對基本符號求餘數,得到的新值回代到函式中再次計算(如,8的最大基本符號為V,8對5求宇得到3,3回代到函式中得到III,拼接後就能得到VIII)

函式一:將輸入的數字num轉為string形式,呼叫enumerate函式訪問其數值部分的每一位(如輸入94,就迴圈兩次,tm_num在兩次迴圈中的值分別為90,4)。對於每一次得到的臨時值tm_num,傳入cal函式中,計算得到對應的字串(如90,將返回''XC'')。最後將每次迴圈得到的字串相加,就能得到我們想要的字串了。

函式二:對於一個輸入,我們需要先找到該數值的最大基本符號,因為事先不知道它是多少位的,所以輸入值依次跟1000,500,100....1比較找到其最大基本符號。這一部的實現方法有兩種,迴圈或者遞迴,我是用遞迴實現的,通過控制變數i,j來表示1000,500..1,其中的規律為

比較值的分解ij
1000=2^3+5^333
500  =2^2+5^323
100  =2^2+5^222
50    =2^1+5^212
10    =2^1+5^111
5      =2^0+5^101
1      =2^0+5^000

先將係數i,j初始值設為0,0,等於3,3時結束,判斷兩個值是否相等,相等則j自增1,j>i則i自增1,該規律可以很好地對應上表。以輸入值8為例,在我們的程式碼裡面比較值記為temp,通過與temp的比較,可以確定找到8的最大基本符號值為5,通過字典(結構如下)可以找到最大基本符號。接下來再將8的求餘結果3回代到函式中,求出其餘數部分對應的字串。

{'1':'I','5':'V','10':'X','50':'L','100':'C','500':'D','1000':'M'}

因為題目有要求要對4,9這樣的數字進行轉換,按照上面的部分,對4的輸出結果為:IIII。因此需要一些額外的判斷和處理,觀察發現這些數都有一個特徵:加上一個值,就等於基本符號了。但是4,9需要加一個1,40、90需要加一個10。實際上我們可以使用上表定義的變數i,計算得到的10^i這就是我們需要增加的那個量。只要對一個輸入加一個判斷,當加上這樣一個量時是否為一個基本符號,就能找出所有的特殊情況。對於4,或者9這樣的數,因為其對應的字串為IV、IX。以IV為例,可以將字串分為兩部分I和V,找到它的基本單位值1(就是上面的10^i),列印這個值對應的羅馬數字I,然後將4+1傳入遞迴函式中,得到字串5。相應的,40就是先找到字元X,再將50傳回遞迴函式,得到L。

以上,我們就對一般情況和特殊情況都做了處理。下面為具體的程式碼實現,有詳細的註釋:

class Solution(object):
    def intToRoman(self, num, i=0, j=0):
        """
        :type num: int
        :rtype: str
        """
        strx=''
        str_num=str(num)                         #將數字轉為字串
        for indx,value in enumerate(str_num):    #遍歷str_num
            tm_num=int(str_num[indx])*10**(len(str_num)-(indx+1)) #tm_num表示num分解後的的每一位
            strx+=self.cal(tm_num)               #將每一位對應值代入cal函式中,計算得到對應的羅馬數字字串
        return strx                              #返回結果

    def cal(self,num,i=0,j=0):    
        str1=''                                
        str2=''
        val={'1':'I','5':'V','10':'X','50':'L','100':'C','500':'D','1000':'M'} #羅馬字元與阿拉伯數值對應轉換字典
        temp=1000/(2**i*5**j)                    #temp為羅馬數字基本符號值,由i,j決定,從1000-500..5-1
        base_value=10**(3-i)                     #基本值,當前數值對應的基本量,如4對應的1,40對應10
        if(i==j):                                #這裡的if和elif是對特殊情況的處理,因為i,j是從0,0到3,3.
            tm_i=i                               #對於特殊情況的輸入,需要還原出其的上一級對應的i,j
            tm_j=j-1                             #以4為例,滿足4>1時,i和j的值為3,3.因為要輸出IV.I可以由base_value確定
            i+=1                                 #V可以將4+1回代cal函式得到5對應的V,因為此時i,j值對應的最大基本符號為I
        elif(i>j):                               #所以需要對i,j處理一下,對應最大基本符號V,並與4+1一起回代到cal中
            tm_i=i-1
            tm_j=j
            j+=1
        if(num>=temp):                           #找出num的最大基本符號
            if((base_value+num)==(1000/(2**tm_i*5**tm_j))): #判斷一個值是否為特殊情況,即,num+base_value是否等於基本符號
                str1=val['%d'%base_value]        #將基本符號對應的字元放入str1中,如IX,將I放入str1中
                num+=base_value                  #將num更新為num+base_value,如,num=40 -> num=50
                i=tm_i                           #更新i,j的值
                j=tm_j
            else:                                #一般情況下
                str1=val['%d'%temp]*(num/temp)   #str1為num的基本字元*次數,如3,則str1='III'
                num=num%temp                     #num更新為num的餘數
        if((i<4)&(j<4)):                         #i,j的變化範圍
            str2=self.cal(num,i,j)               #新的num,i,j回代到cal中,計算得到str2
        return str1+str2                         #返回結果