题目出处
实现罗马数字与整数的互转。 数字大小为[1, 3999]之间。
罗马数字
罗马数字字母
罗马数字只有7个字母组成,每个字母代码的字如下
字母 | M | D | C | L | X | V | I |
代表数字 | 1000 | 500 | 100 | 50 | 10 | 5 | 1 |
四个规则
- 相同的数字连写, 所表示的数等于这些数字相加得到的数。如 XXX表示 30
- 小的数字在大的数字的右边, 所表示的数等于这些数字相加得到的数 如VIII 表示8
- 小的数字(限于I, X, C)在大的数字的左边, 所表示的数等于大数减去小的数: 如IV 表示4
- 在一个数的上面画一条横线, 表示这个数增值1000倍(由于题目只考虑4000以内的数,所以这条规则不用考虑)。
五个组数规则
- I, X, C: 最多只能连用3个, 如果放在大数的左边,只能用1个。
- V, L, D: 不能放在大数的左边,只能使用一个。
- I 只能用在V和X的左边。 IV表示4, IX表示9
- X只能放在L,C左边。 XL 表示40, XC表示90
- C只能用在D, M左边。 CD 表示400, CM表示900
分析
这里面有个麻烦的点, 就是数字可以放在左边也可以放在右边。那就让处理逻辑没那么顺。
如果都只能放在右边,那样就可以直接使用加法。如9表示为 IX, 而如果表示为 VIIII,这样处理相加就OK.
对于整数转罗马数字:可以使用组合数字来进行拆分,使程序能够实现连加的方法。
对于罗马数字转整数: 需要得用放在大数左边的数字只能使用一个的特点来判断对当前字母是加还是减。
代码
整数转罗马数字
string intToRoman(int num) {
if(num <= 0) return "";
string ret = "";
static int number[13] = {1000, 900, 500, 400, 100,90, 50, 40, 10, 9, 5, 4, 1};
static string flags[13] = {"M","CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"};
for(int i = 0; i < 13 && num > 0; i++){
if(num < number[i]) continue;
// cout<< i << " " << number[i] << " - " <<flags[i] << endl;
while(num >= number[i]){
num-= number[i];
ret += flags[i];
}
}
return ret;
}
罗马数字转整数
int romanToInt(string s) {
int tagVal[256];
tagVal['I'] = 1;
tagVal['V'] = 5;
tagVal['X'] = 10;
tagVal['C'] = 100;
tagVal['M'] = 1000;
tagVal['L'] = 50;
tagVal['D'] = 500;
int val = 0;
for(int i = 0; i < s.length(); i++){
if(i+1 >= s.length() || tagVal[s[i+1]] <= tagVal[s[i]])
val += tagVal[s[i]];
else
val -= tagVal[s[i]];
}
return val;
}