罗马数字包含以下七种字符: I, V, X, L,C,D 和 M。
字符 数值
I 1
V 5
X 10
L 50
C 100
D 500
M 1000
例如, 罗马数字 2 写做 II ,即为两个并列的 1。12 写做 XII ,即为 X + II 。 27 写做 XXVII, 即为 XX + V + II 。
通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做 IIII,而是 IV。数字 1 在数字 5 的左边,所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地,数字 9 表示为 IX。这个特殊的规则只适用于以下六种情况:
I 可以放在 V (5) 和 X (10) 的左边,来表示 4 和 9。
X 可以放在 L (50) 和 C (100) 的左边,来表示 40 和 90。
C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900。
给定一个罗马数字,将其转换成整数。输入确保在 1 到 3999 的范围内。
示例 1:
输入: "III" 输出: 3
示例 2:
输入: "IV" 输出: 4
一. 题目分析
该题难点:
1) 对于特殊情况得判断,
2)对于复杂输入以及非法输入得判断
方案一(C++实现):
构建一个字典表,存储罗马数据与数值,然后遍历该数值,将每个罗马字符所代表得数值依次相加即可,重点在于六种特殊情况得判断。代码如下:
1 class Solution { 2 public: 3 int romanToInt(string RomanStr) { 4 int index = 0; 5 int ans = 0; 6 map <char, int> table = { 7 {'I',1}, 8 {'V',5}, 9 {'X',10}, 10 {'L',50}, 11 {'C',100}, 12 {'D',500}, 13 {'M',1000} 14 }; 15 while(RomanStr[index] != '\0') 16 { 17 int key_i = 0; 18 switch(RomanStr[index]) 19 { 20 case 'I': 21 switch(RomanStr[index+1]) 22 { 23 case 'V': 24 ans += 4; 25 index += 2; 26 continue; 27 case 'X': 28 ans += 9; 29 index += 2; 30 continue; 31 } 32 case 'X': 33 switch(RomanStr[index+1]) 34 { 35 case 'L': 36 ans += 40; 37 index += 2; 38 continue; 39 case 'C': 40 ans += 90; 41 index += 2; 42 continue; 43 } 44 case 'C': 45 switch(RomanStr[index+1]) 46 { 47 case 'D': 48 ans += 400; 49 index += 2; 50 continue; 51 case 'M': 52 ans += 900; 53 index += 2; 54 continue; 55 } 56 default: 57 ; 58 } 59 ans += table[RomanStr[index]]; 60 index++; 61 } 62 return ans; 63 } 64 };
如上是我自己写得代码,LeetCode上也能运行通过,但有以下问题:
1) 针对一些复杂输入时,可能出现错误得错过,而且没有对输入得罗马字符串进行合理性判断,这个是需要吗?打个问号?
2)接上面问题,如果出现ICM这种格式得数据,怎么结合呢?如果输入"IDM",这样得数据是否合理呢?
方案二:
参考了别人从数学原理得计算方法,改进了下方案:
本质上采用得思想是,判断当前数据与下一个数据得大小,如果小于,则加上前一个数据得负值。目前看来该种方法是比较简单得方式,逻辑简单清晰。但同样有上述有疑问:对于某些复杂输入得判断如何进行
1 class Solution { 2 public: 3 int romanToInt(string RomanStr) { 4 map <char, int> table = { 5 {'I',1}, 6 {'V',5}, 7 {'X',10}, 8 {'L',50}, 9 {'C',100}, 10 {'D',500}, 11 {'M',1000} 12 }; 13 int ans = 0; 14 for(int index=0; index<RomanStr.size(); index++) 15 { 16 if (table[RomanStr[index]] < table[RomanStr[index+1]]) 17 { 18 ans -= table[RomanStr[index]]; 19 } 20 else 21 ans += table[RomanStr[index]]; 22 } 23 printf("ans = %d\n",ans); 24 return ans; 25 } 26 };
二. 总结分析
1) 学习到了一种方法,在碰到一个题目,更多得查看其在数学上得规律与原理,而不是宏观得跟随着变化去解题
2) 学到了C++中对Hash表得一种使用方法,即通过map来简历数据表
3) while()循环中遇到switch时,如果条件符合跳过循环,直接使用continue即可,break生效得时switch,而continue生效得时while