LeetCodeOJ刷題之12【Integer to Roman】

Integer to Roman

Given an integer, convert it to a roman numeral.
Input is guaranteed to be within the range from 1 to 3999.
意思就是:
給出一個整數 num( 0<=num<=3999),返回其對應的羅馬數字表示;
羅馬數字有:git

I V X L C D M
1 5 10 50 100 500 1000

Solutions

  • 1 Integer to Roman -- 143ms
    • 這個方式不知道爲何很慢,是我第一個想出的幾乎至關於暴力的方法。
    class Solution {
    public:
        string intToRoman(int num) {
            if(num<=0||num>3999)return string();
            map<int,string> one,two,three,four;  //這裏使用的是 Map
            one[0]="";      two[0]="";      three[0]=""; 
            one[1]="I";     two[1]="X";     three[1]="C";       four[1]="M";
            one[2]="II";    two[2]="XX";    three[2]="CC";      four[2]="MM";
            one[3]="III";   two[3]="XXX";   three[3]="CCC";     four[3]="MMM";
            one[4]="IV";    two[4]="XL";    three[4]="CD";  
            one[5]="V";     two[5]="L";     three[5]="D";  
            one[6]="VI";    two[6]="LX";    three[6]="DC";  
            one[7]="VII";   two[7]="LXX";   three[7]="DCC";  
            one[8]="VIII";  two[8]="LXXX";  three[8]="DCCC";  
            one[9]="IX";    two[9]="XC";    three[9]="CM";
    
            int mod=0,idx=1;
            string rs="",tmp="";
            while(num>0){
                mod=num%10;
                switch(idx){
                    case 1:{
                        tmp=one[mod];
                        rs=tmp+rs;
                        break;
                    }
                    case 2:{
                        tmp=two[mod];
                        rs=tmp+rs;
                        break;
                    }
                    case 3:{
                        tmp=three[mod];
                        rs=tmp+rs;
                        break;
                    }
                    case 4:{
                        tmp=four[mod];
                        rs=tmp+rs;
                        break;
                    }
                }
                num=num/10;
                ++idx;
            }
            return rs;
        }
    };
    後來通過了測試,發現貌似主要緣由在於使用了 map,因此在第二次測試中將 map 改成了 string 數組
  • 2 Integer to Roman -- 68ms
    • 果真,改進後,運行時間從原來的 143ms 變成了 68ms ,這是第一個改進:
    //原來的 map
    map<int,string> one,two,three,four;  //這裏使用的是 Map
    //改進後
    string* one=new string[10],*two=new string[10],*three=new string[10],*four=new string[4];
  • 3 Integer to Roman -- 54ms
    • 方法1和2中,使用了很大的空間來存儲所有的羅馬特殊數字,增長了空間複雜性,因此我就想,能不能不存儲這些特殊數字,只存儲最基本的羅馬基數數字 IVXLCDM ,而後根據當前數字進行判斷,生成對應的羅馬數字。下面是這一思想的代碼:
    class Solution {
    public:
        string intToRoman(int num) {
            if(num<=0||num>3999)return string();
            string roman="IVXLCDM";  //存儲基數
            string rs="",tmp="";
            int ndx=0,mod=0;  // ndx 用來記錄當前基數(即第n位對應的最小羅馬數字座標)
            while(num>0){
                mod=num%10; //求餘數
                if(ndx==6){ //千位只有 M
                    rs=string(mod,'M')+rs;
                    break;
                }
                if(mod==0){
                    tmp="";
                }else if(mod<4){
                    tmp=string(mod,roman[ndx]);
                }else if(mod==4){
                    tmp=string(1,roman[ndx])+string(1,roman[ndx+1]);
                }else if(mod<9){
                    tmp=string(1,roman[ndx+1])+string(mod-5,roman[ndx]);
                }else if(mod==9){
                    tmp=string(1,roman[ndx])+string(1,roman[ndx+2]);
                }
                rs=tmp+rs;
                ndx+=2; //基數向前進2個
                num/=10;
            }
            return rs;
        }
    };
    • 這一思想中,有兩點是須要考慮的:
      1. 千位只有 M
      2. 數字4 , 9很特殊;
    • 對於數字 4 來講,若是當前基數座標爲 ndx ,則其對應的羅馬數字爲:
    string(1,roman[ndx])+string(1,roman[ndx+1]);
    好比當前位爲十位,則 ndx=2; roman[ndx]='X'; roman[ndx+1]='L' ; 對應羅馬數字爲: XL
    • 對於數字 9 來講,對應羅馬數字爲:
    string(1,roman[ndx])+string(1,roman[ndx+2]);
    好比當前位爲十位,則 ndx=2; roman[ndx]='X'; roman[ndx+2]='C' ; 對應羅馬數字爲: XC
    • 小於 4 的數字 mod,則爲 mod 個連續基數;
    • 大於 4 小於 9 的數字 mod , 則爲 一個 roman[ndx+1]mode-5 個連續基數;
    • 同時,這個版本中,我發覺仍是能夠改進一下的,對於代碼的改進,因此出現了方法4
  • 4 Integer to Roman -- 48ms
    • 對於代碼的進行,方法3中會產生大量的string臨時變量,所以這裏儘可能的使用了迭代器和 string 的insert方法進行處理。代碼運行效率得以再次提升:48ms
    class Solution {
    public:
        string intToRoman(int num) {
            if(num<=0||num>3999)return string();
            char roman[]="IVXLCDM";
            string rs="";
            int ndx=0,mod=0;
            while(num>0){
                mod=num%10;
                if(ndx==6){
                    rs=string(mod,'M')+rs;
                    break;
                }
                if(mod<4){
                    rs=string(mod,roman[ndx])+rs;
                }else if(mod==4){
                    rs.insert(rs.begin(),roman[ndx+1]);
                    rs.insert(rs.begin(),roman[ndx]);
                    // rs=string(1,roman[ndx])+string(1,roman[ndx+1])+rs;
                }else if(mod<9){
                    // rs=string(1,roman[ndx+1])+string(mod-5,roman[ndx])+rs;
                    rs=string(mod-5,roman[ndx])+rs;
                    rs.insert(rs.begin(),roman[ndx+1]);
                }else if(mod==9){
                    rs.insert(rs.begin(),roman[ndx+2]);
                    rs.insert(rs.begin(),roman[ndx]);
                    // rs=string(1,roman[ndx])+string(1,roman[ndx+2])+rs;
                }
                ndx+=2;
                num/=10;
            }
            return rs;
        }
    };
  • 5 Integer to Roman -- 57ms
    • 這是LeetCode上網友的答案,感受跟簡潔,同時算法也很容易理解,和這裏第一種的思想很像:
    class Solution {
    public:
        string intToRoman(int num) {
            string M[] = {"", "M", "MM", "MMM"};
            string C[] = {"", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"};
            string X[] = {"", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"};
            string I[] = {"", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"};
            return M[num/1000] + C[(num%1000)/100] + X[(num%100)/10] + I[num%10];
        }
    };
    • 但這裏有一個問題,就是這種方法的思想和第二種很像,可是運行時間卻更少,因而我將第二種的方法又進行了改進,我感受差別應該是出如今:第二種方法在賦值時是先定義後賦值,且使用了 new 操做符,這裏沒有!因此有了下一個簡單的改進:
    • 方法二的四個字符串數組,使用方法 5 的方式定義賦值。運行後時間爲 58ms,果真這個是緣由!看來之後對於內容不是不少的字符數組應該優先不使用 new ,這裏還要注意的是,我在第二種方法裏 new 的那些個字符數組~~~,忘了一個很重要的操做:delete 。😱
  • 6 Integer to Roman -- 49ms
    • 這個是網友的答案:
    class Solution {
    public:
        string intToRoman(int num) {
            // IMPORTANT: Please reset any member data you declared, as
            // the same Solution instance will be reused for each test case.    
            string result = "";
            int base[] = {1000,500,100,50,10,5,1,0};
            char baseC[] = {'M','D','C','L','X','V','I'};
            int basen = 0;
            while(num) {
                if(basen%2 == 0 && num/base[basen] == 4) {
                    result += baseC[basen];
                    result += baseC[basen-1];
                    num -= base[basen] * 4;
                } else if(num >= base[basen]) {
                    result += baseC[basen];
                    num -= base[basen];
                } else if(basen%2 == 0 && num / base[basen+2] == 9) {
                    result += baseC[basen+2];
                    result += baseC[basen];
                    num -= base[basen+2]*9;
                } else {
                    basen++;
                }
            }
            return result;
        }
    };
    • 代碼呢,一會兒看思路不是很清楚,感受思想好像有點複雜。
    • 網友給出的思路是這樣的:
      1. 若是 num 是 x 的 4 的倍數(其中,x=1000,100,10,1),則增長一個 x 對應的羅馬數字和 5x 對應的對應的羅馬數字;
        如:400是100的4倍,則增長一個100對應的羅馬數字 C ,和5*100=500對應的羅馬數字 D,則 400=CD ;
      2. 若是 num > x ,則添加一個 x 對應的羅馬數字;
        如: 6 > 5 ,則添加一個 5 對應的羅馬數字 V ;
      3. 若是 num < x (x=1000,100,10,1),可是 num 是 x/10 的 9 倍,則添加一個 x/10 對應的數字和 x 對應的數字。
        如: 90 < 100 ,但 90==9*(100/10) ,則添加一個 (100/10)=10 對應的羅馬數字 X 和一個 100 對應的羅馬數字 C ,則 90=XC;
    • 我的以爲這個算法有點複雜!不過仍是挺高效的。這裏學習一下思想。

附錄

同系列:LeetCodesOJhttp://www.cnblogs.com/lomper/tag/LeetCodesOJ/github

相關文章
相關標籤/搜索