1. 程式人生 > >LeetCode之Roman & Integer 的轉換(簡單題)

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;
    }
};