LeetCode.12-整數轉羅馬數字符串(Integer to Roman)

這是悅樂書的第351次更新,第376篇原創

java

01 看題和準備

今天介紹的是LeetCode算法題中Medium級別的第6題(順位題號是12)。羅馬數字由七個不一樣的符號表示:I,V,X,L,C,D和M.算法

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

例如,2用羅馬數字寫成II,由兩個I加在一塊兒。12寫爲XII,簡稱爲X + II
27寫成XXVII,即XX + V + II數組

羅馬數字一般從左到右從最大到最小。可是,四個數字不是IIII。相反,4寫爲IV
由於IV以前,咱們作減法獲得4。一樣的原則適用於9,9被寫爲IX。有六個使用減法的實例:數據結構

I能夠放在V(5)和X(10)以前,獲得4和9。
X能夠放在L(50)和C(100)以前,獲得40和90。
C能夠放在D(500)和M(1000)以前,獲得400和900。app

給定一個整數,將其轉換爲羅馬數字。輸入保證在1到3999的範圍內。例如:ui

輸入:3
輸出:「III」code

輸入:4
輸出:「IV」字符串

輸入:9
輸出:「IX」class

輸入:58
輸出:「LVIII」
說明:L = 50,V = 5,III = 3。基礎

輸入:1994
輸出:「MCMXCIV」
說明:M = 1000,CM = 900,XC = 90,IV = 4。

02 第一種解法

題目要求咱們將整數轉成羅馬數字符串來表示,和以前遇到的羅馬數字符串轉整數正好相反。

題目限定了num的範圍,[1,3999],針對常見的數字,列了下面這些羅馬數和整數的對應關係:

900  CM    90  XC    9  IX

           800  DCCC  80  LXXX  8  VIII 
           700  DCC   70  LXX   7  VII
           600  DC    60  LX    6  VI
           500  D     50  L     5  V

           400  CD    40  XL    4  IV

3000  MMM  300  CCC   30  XXX   3  III
2000  MM   200  CC    20  XX    2  II
1000  M    100  C     10  X     1  I

咱們能夠將他們的對應關係分爲4組:

  • 第一組,最高位小於4,他們對應的羅馬數是疊加的,例如1000是M,3000是MMM

  • 第二組,最高位等於4,他們對應的羅馬數是在以5開頭羅馬數前加上以1開頭的羅馬數,且二者是相鄰的關係。

  • 第三組,最高位在5到8之間,對應的羅馬數是以5開頭的羅馬數爲基礎,後跟上疊加的1開頭的羅馬數,二者也是相鄰的關係。

  • 第四組,最高爲等於9,對應的羅馬數是以1開頭的羅馬數間隔組合,例如900,在表明1000的M前加表明100的C,即CM,二者中間間隔一位。

根據以上的對應關係組合,咱們將不一樣整數、羅馬數字符串初始化爲數組,由高位到低位,依次計算羅馬數。

public String intToRoman(int num) {
    String[] roman = {"M", "D", "C", "L", "X", "V", "I"};
    int[] value = {1000, 500, 100, 50, 10, 5, 1};
    StringBuilder sb = new StringBuilder();
    for (int i=0; i<value.length; i+=2) {
        // 獲得當前num的最高位
        int tem = num/value[i];
        if (tem < 4) {
            // 疊加
            for (int j=0; j<tem; j++) {
                sb.append(roman[i]);
            }
        } else if (tem == 4) {
            // 相鄰
            sb.append(roman[i]+roman[i-1]);
        } else if (tem > 4 && tem < 9) {
            // 相鄰
            sb.append(roman[i-1]);
            for (int j=6; j<=tem; j++) {
                sb.append(roman[i]);
            }
        } else if (tem == 9) {
            // 間隔兩位
            sb.append(roman[i]+roman[i-2]);
        }
        // 去掉已經參與計算的高位
        num = num%value[i];
    }
    return sb.toString();
}


03 第二種解法

在第一種解法的基礎上,咱們將初始數組中的元素分別對應增長了6位,以9和4開頭。依舊是從高位往低位計算,與第一種解法中利用取餘、取整不一樣,此解法是循環作減法,直到num剩下的值小於當前須要減去的值,纔會尋找下一個須要減去的數。

public String intToRoman2(int num) {
    String[] roman = {"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};
    StringBuilder sb = new StringBuilder();
    for (int i=0; i<value.length; i++) {
        while (num >= value[i]) {
            sb.append(roman[i]);
            num -= value[i];
        }
    }
    return sb.toString();
}


04 第三種解法

還有一種取巧的解法。由於題目限定num的範圍,最高不會超過4000,咱們能夠把num拆成4個部分,千位只有四種可能,0(num是一個三位數)、一、二、3,百位對應的有10種可能,0到9,十位和個位也是10種可能,只須要將他們都列出來,依次取num中不一樣位對應的字符串便可。

此解法的時間複雜度是O(1)

public static String intToRoman3(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];
}


05 小結

算法專題目前已連續日更超過六個月,算法題文章219+篇,公衆號對話框回覆【數據結構與算法】、【算法】、【數據結構】中的任一關鍵詞,獲取系列文章合集。

以上就是所有內容,若是你們有什麼好的解法思路、建議或者其餘問題,能夠下方留言交流,點贊、留言、轉發就是對我最大的回報和支持!

相關文章
相關標籤/搜索