在看《dive into python》的單元測試時,發現用作例子的「阿拉伯數字-羅馬數字」的轉換演算法非常的巧妙,現在發上來和大家分享一下。
romannumeralmap = (('m',1000),
('cm',900),
('d',500),
('cd',400),
('c',100),
('xc',90),
('l',50),
('xl',40),
('x',10),
('ix',9),
('v',5),
('iv',4),
('i',1))
def toroman(n):
result = ""
for numeral, integer in romannumeralmap:
while n >= integer:
result += numeral
n -= integer
return result
def fromroman(s):
result = 0
index = 0
for numeral, integer in romannumeralmap:
while s[index:index+len(numeral)] == numeral:
result += integer
index += len(numeral)
return result
print toroman(1356)
print fromroman('mcmlxxii')
這個演算法的聰明之處,就在於他通過乙個romannumeralmap,把羅馬數字與阿拉伯數字裡面的「邊界值」做出一一對應。這個邊界剛剛好是羅馬數字組合之間的轉換。例如,i,ii,iii都可以通過第乙個邊界值組合獲得;v,vi,vii,viii可以通過v和i的組合獲得。而對於一些特殊的值,則直接列出來。例如iv。通過這個邊界值的組合,就能實現所需求的轉換。這就類似於在一些機讀卡上,需要填寫1到100的數字,他會使用0,1,2,4,7這樣以來:
3 = 1 + 2;
5 = 4 + 1;
6 = 4 + 2;
8 = 7 + 1;
9 = 7 + 2.
首先看一下toroman()函式,把阿拉伯數字轉換成羅馬數字。它使用python連線字串的操作符號 + 來使「邊界值」連線到一起。例如用作例子的n = 1356,程式遍歷romannumeralmap,尋找n對應的羅馬數字,如果找不到,那就找剛剛比n小一點的數字對應的羅馬字元。遍歷在能使n 在romannumeralmap有對應值時結束。
找到剛剛比1356小的那個值對應的羅馬數字,也就是1000,m
再繼續找剛剛比n = 1356 - 1000 = 356小的數,也就是100,c;
又繼續找比n = 356 - 100 = 256小的數,還是100,也就是c;
再找比n = 256 - 100 = 156小的數,仍然是100,c;
繼續找比n = 156 - 100 = 56 小的數,50,l;
繼續找比n = 56 - 50 = 6小的數,5,v;
繼續找n = 6 - 5 = 1對於的數,1,i。 結束。
所以1356對應的值為mccclvi。 這樣的操作很類似於在十進位制裡面,乙個數字1356 = 1000 + 300 + 50 + 6,只是阿拉伯數字裡面6是乙個單獨的符號,而羅馬數字裡面vi是個v + i的組合而已。
下面再說說fromroman()函式,把羅馬數字轉換成阿拉伯數字。這個函式在理解上面可能比toroman()稍稍要困難一點。
還是用例子來說明,mcmlxxii轉換成阿拉伯數字。其中如下**
s[index:index+len(numeral)]
作用是把字串s中,從第index位到第index+ len(numeral)位(不包含第index + len(numeral)位自身)的字元提取出來。比如:
>>> a = 'helloworld'
>>> print a[2:5]
llo
即s的第2,3,4位被取出。
回到對s = 'mcmlxxii'的處理。
首先map中第乙個羅馬字元是m,只有一位,就把s 的第0位拿出來對比,發現s的第0位剛剛好是m,於是得到乙個1000,index變為1,則之後從s的第一位開始。簡單的說,相當於s 變成了s = 'cmlxxii'
接下來,經過一些無效的值以後,輪換到cm,發現cm為兩位,就取出s的前兩位,也就是cm,發現在s中剛剛好有cm,於是得到900. index再加2,則實際上s就相當於變成了lxxii
繼續經過一些無效值以後,輪換到了l,發現s當前的1位為l,於是在map中有對應的值50.然後index加1,s相當於變成了xxii
接下來到了x,發現s當前的1位為x,在map中有對應的值10.然後index 再加1,s變成了xii
雖然這個時候人已經知道是12了,但是計算機還是不知道,於是繼續乙個x,s變為ii
然後出現乙個i,s變為i
終於程式找到了乙個直接相等的值i,於是轉換結束。
所以mcmlxxii對於的阿拉伯數字是1000+900+50+10+10+1+1 = 1972
這個方法,把乙個羅馬數字從高位開始逐次剝離最高位,從而漸漸的把數字縮小。
最近正在學習演算法。因為越來越發現現在做的東西,如果僅僅實現功能的話,效能會出現瓶頸。希望我以後能寫出更好的演算法。
羅馬數字轉換阿拉伯數字0 3999
有兩條須注意掌握 1.基本數字 x c 中的任何乙個 自身連用構成數目 或者放在大數的右邊連用構成數目 都不能超過三個 放在大數的左邊只能用乙個 2.不能把基本數字 v l d 中的任何乙個作為小數放在大數的左邊採用相減的方法構成數目 放在大數的右邊採用相加的方式構成數目 只能使用乙個 基本字元 i...
阿拉伯數字轉羅馬數字
最開始想的是當成進製轉,比如說 1 i,2 ii,5 v,6 vi public static string inttoroman1 int num int radix stringbuffer sb new stringbuffer for int i radix.length 1 i 0 i r...
阿拉伯數字轉羅馬數字
時間限制 c c 1秒,其他語言2秒 空間限制 c c 262144k,其他語言524288k 64bit io format lld 題目描述 張老師需要用數字來統計學生們的得分情況,但阿拉伯數字已經不能滿足他的要求了,所以想請你幫忙將學生的成績轉換成羅馬數字。羅馬數字是由七個不同的符號來表示 i...