12. Integer to Roman
Roman numerals are represented by seven different symbols: I
, V
, X
, L
, C
, D
and M
.
Symbol Value
I 1
V 5
X 10
L 50
C 100
D 500
M 1000
For example, two is written as II
in Roman numeral, just two one's added together. Twelve is written as, XII
, which is simply X
+ II
. The number twenty seven is written as XXVII
, which is XX
+ V
+ II
.
Roman numerals are usually written largest to smallest from left to right. However, the numeral for four is not IIII
. Instead, the number four is written as IV
. Because the one is before the five we subtract it making four. The same principle applies to the number nine, which is written as IX
. There are six instances where subtraction is used:
I
can be placed beforeV
(5) andX
(10) to make 4 and 9.X
can be placed beforeL
(50) andC
(100) to make 40 and 90.C
can be placed beforeD
(500) andM
(1000) to make 400 and 900.
Given an integer, convert it to a roman numeral. Input is guaranteed to be within the range from 1 to 3999.
Example 1:
Input: 3
Output: "III"
Example 2:
Input: 4
Output: "IV"
Example 3:
Input: 9
Output: "IX"
Example 4:
Input: 58
Output: "LVIII"
Explanation: C = 100, L = 50, XXX = 30 and III = 3.
Example 5:
Input: 1994
Output: "MCMXCIV"
Explanation: M = 1000, CM = 900, XC = 90 and IV = 4.
这一次题目是把数字和罗马数字进行转换。
这个题目提示很充足,因为根据这些罗马基本数字,我们起码要先分7类,来储存7个罗马数字。后面还给出了6个罗马数字,也就是4,9,40,90,400,900对应的罗马数字,于是可以直接分13类,用一个结构体或者类把他们绑定起来,如果是用python可以直接用字典绑定起来,可能会更方便。
然后经过思考,注意到,4,9,40,90,400,900作为输出结果肯定最多只能出现一次,例如8,我们会用VIII来表示而不是IVIV,而7个基本罗马数字是可以多次使用的,8也有用了3个I,于是就从大到小排列,先写一个结构体数组。
也就是说,我们可以用这样的一个数组num[13] = {1000,900,500,400,100,90,50,40,10,9,5,4,1}把这些信息储存了,用结构体或者类把数字和罗马数字绑定。
由于在C++,数组下标是从0开始的,num[0] = 1000。
所以我们可以注意到,偶数下标的都是基本罗马数字,奇数下标的都是组合而来的罗马数字。
那算法具体思路就如下所示了:从大到小一级一级作差求解,对于偶数下标,因为这些数字可以重复使用,所以首先用输入数字除以偶数下标对应的值,求出来使用的次数,然后作差。对于奇数下标,只需要减一次就好了。然后我们可以得出一个新数组,分别代表了这些罗马数字出现的次数,从大到小输出即可。
代码如下:
#include <iostream>
#include <string>
using namespace std;
class ptlist
{
private:
string roman;
int number;
public:
ptlist() {
}
void set(string roman, int number) {
this->roman = roman;
this->number = number;
}
int getNumber() {
return number;
}
string getRoman() {
return roman;
}
}ptl[13];
void setptl()
{
//设置数组
ptl[0].set("M", 1000);
ptl[1].set("CM", 900);
ptl[2].set("D", 500);
ptl[3].set("CD", 400);
ptl[4].set("C", 100);
ptl[5].set("XC", 90);
ptl[6].set("L", 50);
ptl[7].set("XL", 40);
ptl[8].set("X", 10);
ptl[9].set("IX", 9);
ptl[10].set("V", 5);
ptl[11].set("IV", 4);
ptl[12].set("I", 1);
}
int counter[13] = {};
class Solution
{
public:
string intToRoman(int num) {
setptl();
int temp;
for (int i = 0; i < 13; i++) {
//如果是偶数下标,需要求出该罗马数字出现的次数
if (!(i % 2)) {
temp = num / ptl[i].getNumber();
counter[i] = temp;
num -= temp * ptl[i].getNumber();
}
else {
//如果是奇数下标,只需要判断该罗马数字是否能出现一次即可
if (num >= ptl[i].getNumber()) {
counter[i] = 1;
num -= ptl[i].getNumber();
}
}
}
string result = "";
for (int i = 0; i < 13; i++) {
while (counter[i]) {
result += ptl[i].getRoman();
counter[i]--;
}
}
return result;
}
};
int main()
{
Solution ss;
int a;
cin >> a;
cout << ss.intToRoman(a) << endl;
return 0;
}