题目链接:Integer to Roman

Given an integer, convert it to a roman numeral.

Input is guaranteed to be within the range from 1 to 3999.

这道题的要求是将整数转化成罗马数字,其中输入数据范围是1到3999。

罗马数字是最早的数字表示方式,比阿拉伯数字早2000多年,起源于罗马。

罗马数字的计数方法:(出自百度百科

罗马字符    I   V   X   L   C   D   M
整数数字    1   5   10  50  100 500 1000
  1. 相同的数字连写,所表示的数等于这些数字相加得到的数,如:III = 3;
  2. 小的数字在大的数字的右边,所表示的数等于这些数字相加得到的数, 如:VIII = 8;XII = 12;
  3. 小的数字,(限于I、X 和C)在大的数字的左边,所表示的数等于大数减小数得到的数,如:IV= 4;IX= 9;
  4. 正常使用时,连写的数字重复不得超过三次。(表盘上的四点钟“IIII”例外)
  5. 在一个数的上面画一条横线,表示这个数扩大1000倍。(本题用不到这点)

有几条须注意掌握:

  1. 基本数字I、X、C中的任何一个,自身连用构成数目,或者放在大数的右边连用构成数目,都不能超过三个;放在大数的左边只能用一个。
  2. 不能把基本数字V、L、D中的任何一个作为小数放在大数的左边采用相减的方法构成数目;放在大数的右边采用相加的方式构成数目,只能使用一个。
  3. V和X左边的小数字只能用I,且只能有1个。
  4. L和C左边的小数字只能用X,且只能有1个。
  5. D和M左边的小数字只能用C,且只能有1个。

看懂了上面的规则后,就可以对数字的每位逐个判断即可。可以归纳出如下4种情形:

  1. 如果该位数字是9,则说明是上面3、4、5这三种情况中的一种,即把I、X、C中的一个放到了大数字的左侧;
  2. 如果该位数字是5~8,则说明是上面1这种情况,即I、X、C中的一个,自身连用或者放在大数的右边连用;
  3. 如果该位数字是4,则说明同样是上面3、4、5这三种情况中的一种,即把I、X、C中的一个放到了大数字的左侧;
  4. 如果该位数字是0~3,则同样说明是上面1这种情况,即I、X、C中的一个,自身连用或者放在大数的右边连用。

时间复杂度:O(n)

空间复杂度:O(1)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
class Solution
{
public:
    string intToRoman(int num)
    {
        string s;
        int n1[] = {1000, 100, 10, 1};
        char r1[] = {'M', 'C', 'X', 'I'};
        char r2[] = {' ', 'D', 'L', 'V'};
        for(int i = 0; i < 4; ++ i)
        {
            int b = num / n1[i];

            if(b == 9)
                s = s + r1[i] + r1[i-1];
            else if(b >= 5)
            {
                s += r2[i];
                for(int j = 0; j < b - 5; ++ j)
                    s += r1[i];
            }
            else if(b == 4)
                s = s + r1[i] + r2[i];
            else
            {
                for(int j = 0; j < b; ++ j)
                    s += r1[i];
            }

            num = num % n1[i];
        }

        return s;
    }
};

进一步,可以看到,罗马数字可以分为1、4、5、9这四种构成方式,而1-3999中,共有1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1,共计13种,依次分别对应”M”, “CM”, “D”, “CD”, “C”, “XC”, “L”, “XL”, “X”, “IX”, “V”, “IV”, “I”,即:

整数数字  1000 900 500 400 100 90 50 40 10 9  5 4  1
罗马数字  M    CM  D   CD  C   XC L  XL X  IX V IV I

这样,代码长度大大缩短:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Solution
{
public:
    string intToRoman(int num)
    {
        int n[] = {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1};
        string r[] = {"M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"};
        
        string s = "";
        for(int i = 0; num > 0; num %= n[i], ++ i)
            for(int j = 0, k = num / n[i]; j < k; ++ j)
                s += r[i];
        return s;
    }
};