LeetCode之Roman & Integer 的轉換(簡單題)
羅馬數字和現在使用的阿拉伯整數之間的轉換在LeetCode上一共有兩道題目:Roman to Integer 和Integer to Roman
如標題所說的,這是個簡單的字串處理的題目,基本上知道了規則就可以直接寫出程式碼解決了。
羅馬數字基本規則
做好這道題目的前提是知道一些羅馬數字的基本規則。
羅馬數字一共有七個,分別是I(1)、V(5)、X(10)、L(50)、C(100)、D(500)和M(1000)。
按照下面的規則就可以表示所有的正整數了。需要注意的是羅馬數字中沒有“0”,也與進位制無關,所以,一般是將羅馬數字用來記數,不用於演算。
重複次數:一個羅馬數字重複幾次就表示是其幾倍。比如II表示2
右加左減:在較大的羅馬數字右邊記上一個較小的羅數字,則其表示的數字是大數減去小數的結果,比如IV表示4。在較大的羅馬數字左邊記上一個較小的羅數字,則其表示的數字是大數加上小數的結果,比如VI表示6。需要注意的是:左減的數字有限制,僅限於I、X、C。比如45不可以寫成VL,只能是XLV。
同時,左減的時候不可以跨越數位。比如,99不可以用IC(100 - 1)表示,而是用XCIX([100 - 10] + [10 - 1])表示。(就是把每位阿拉伯數字逐位表示。)
左減數字必須是一位,比如8是VIII,而不是IIX。
右加的數字也不可以連續超過三位,比如14是XIV,而非XIIII。(即是有數位限制。)
加線成千:
在羅馬數字的上方加上一條橫線或者加上下標的Ⅿ,表示將這個數字乘以1000,即是原數的1000倍。
同理,如果上方有兩條橫線,即是原數字的1000000(1000^{2})倍。
數位限制:
同一數位最多隻能出現三次,如40不可表示為XXXX,而要表示為XL。
例外:由於IV是古羅馬神話主神朱庇特(即IVPITER,古羅馬字母沒有J和U)的首字,因此有時用IIII代替Ⅳ。
Roman to Integer
有了羅馬數字的基本概念(其實只要知道羅馬數字的基本表示位就可以做這道題目了,但是多瞭解些也沒有什麼壞處 :P),下面就看下如何做這道題目,首先是羅馬數字轉阿拉伯數字。
3999範圍內的羅馬數字不會用到加上劃線的字母
從最後一個字元開始,如果當前字元對應的數字比上一個數字小,那麼就把結果減去當前字元對應的數字,否則加上當前字元對應數字。為了處理邊界情況,在原字串最後新增一個字元,該字元是原來的尾字元。
class Solution {
public:
int romanToInt(string s) {
int map[26 ];
map['I'-'A'] = 1; map['V'-'A'] = 5; map['X'-'A'] = 10; map['L'-'A'] = 50;
map['C'-'A'] = 100; map['D'-'A'] = 500; map['M'-'A'] = 1000;
int res = 0, n = s.size();
s.push_back(s[n-1]);
for(int i = 0; i < n; i++)
{
if(map[s[i]-'A'] >= map[s[i+1 ]-'A'])
res += map[s[i]-'A'];
else res -= map[s[i]-'A'];
}
return res;
}
};
另一種解法:
class Solution {
public:
int romanToInt(string s) {
int map[26];
map['I'-'A'] = 1; map['V'-'A'] = 5; map['X'-'A'] = 10; map['L'-'A'] = 50;
map['C'-'A'] = 100; map['D'-'A'] = 500; map['M'-'A'] = 1000;
int res = 0, n = s.size();
s.push_back(s[n-1]);
for(int i = 0; i < n; i++)
{
if(map[s[i]-'A'] >= map[s[i+1]-'A'])
res += map[s[i]-'A'];
else res -= map[s[i]-'A'];
}
return res;
}
};
Integer to Roman
整數轉羅數字就更簡單了,直接把整數從前向後逐位提出,然後按照其所在的位替換對應的羅馬數字表示即可,如下:
class Solution {
public:
string intToRoman(int num) {
string roman[4][10] = {
{"", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"},
{"", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"},
{"", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"},
{"", "M", "MM", "MMM"}
};
string ret = "";
int digit = 0;
while (num != 0) {
int remain = num % 10;
ret = roman[digit][remain] + ret;
digit++;
num /= 10;
}
return ret;
}
};
另一個更簡潔的解法:
這本題目中,整個羅馬數字的表示體系就是由1,4,5,9,10,40,50,90,100,400,500,900,1000這些構成的
,理解了規則之後就可以這要寫了。
class Solution {
public:
string intToRoman(int num) {
string str;
string symbol[]={"M","CM","D","CD","C","XC","L","XL","X","IX","V","IV","I"};
int value[]= {1000,900,500,400, 100, 90, 50, 40, 10, 9, 5, 4, 1};
for(int i=0;num!=0;++i)
{
while(num>=value[i])
{
num-=value[i];
str+=symbol[i];
}
}
return str;
}
};