题目:Roman to Integer 罗马字符转整数
难度:简单
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 a roman numeral, convert it to an integer. Input is guaranteed to be within the range from 1 to 3999.
Example 1:
Input: "III" Output: 3
Example 2:
Input: "IV" Output: 4
Example 3:
Input: "IX" Output: 9
Example 4:
Input: "LVIII" Output: 58 Explanation: L = 50, V= 5, III = 3.
Example 5:
Input: "MCMXCIV" Output: 1994 Explanation: M = 1000, CM = 900, XC = 90 and IV = 4.
题意解析:
罗马数字包含以下七种字符: I
, V
, X
, L
,C
,D
和 M
。
例如, 罗马数字 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 的范围内。
解题思路一:
从左到右依次遍历,如果遇到类似CM,XC,就需要比较当前位置和下一个位置的元素,并用i+1位置的值减去i位置的值即可。
public int romanToInt(String s) {
if (s == null || s.length() == 0)
return -1;
HashMap<Character, Integer> map = new HashMap<Character, Integer>();
map.put('I', 1);
map.put('V', 5);
map.put('X', 10);
map.put('L', 50);
map.put('C', 100);
map.put('D', 500);
map.put('M', 1000);
int n = s.length();
int rs = 0;
for (int i = 0; i < n; i++) {
if (i+1<n && map.get(s.charAt(i)) < map.get(s.charAt(i+1))){
rs = rs + map.get(s.charAt(i+1))-map.get(s.charAt(i));
i++;
}else
rs = rs + map.get(s.charAt(i));
}
return rs;
}
此算法时间复杂度为O(n),空间复杂度O(n)
提交代码之后:
Runtime: 7 ms, faster than 87.25% of Java online submissions for Roman to Integer.
Memory Usage: 41.9 MB, less than 5.05% of Java online submissions for Roman to Integer.
解题思路二:
逆向遍历,如果遇到i位置的元素比i+1大,那么就加上i位置的元素再减去i+1位置的元素,每次遍历两个元素。
public int romanToInt(String s) {
if (s == null || s.length() == 0)
return -1;
HashMap<Character, Integer> map = new HashMap<Character, Integer>();
map.put('I', 1);
map.put('V', 5);
map.put('X', 10);
map.put('L', 50);
map.put('C', 100);
map.put('D', 500);
map.put('M', 1000);
int len = s.length(), rs = map.get(s.charAt(len - 1));
for (int i = len - 2; i >= 0; i--) {
if (map.get(s.charAt(i)) >= map.get(s.charAt(i + 1)))
rs += map.get(s.charAt(i));
else
rs -= map.get(s.charAt(i));
}
return rs;
}
此算法时间复杂度为O(n/2),即O(n),空间复杂度O(n)
提交代码之后:
Runtime: 7 ms, faster than 87.25% of Java online submissions for Roman to Integer.
Memory Usage: 37.3 MB, less than 34.88% of Java online submissions for Roman to Integer.
效率并没有多大提升。
解题思路三:
依次遍历每一个元素,使用一个变量记录上一个元素的值,如果出现上一个元素的值小于当前元素,那么结果的值要减去两倍的上一个元素的值,比如CM,如果按照每个元素相加的话就加了1100,但是实际上却是900,所以应减去C的值的二倍,同理IV也是一样的,正常加的话就是6,但是实际上只有4,所以应减去I的值的二倍。
public int romanToInt(String s) {
int num = 0;
int l = s.length();
int last = 1000;
for (int i = 0; i < l; i++){
int v = getValue(s.charAt(i));
if (v > last) num = num - last * 2;
num = num + v;
last = v;
}
return num;
}
private int getValue(char c){
switch(c){
case 'I' : return 1;
case 'V' : return 5;
case 'X' : return 10;
case 'L' : return 50;
case 'C' : return 100;
case 'D' : return 500;
case 'M' : return 1000;
default : return 0;
}
}
此算法时间复杂度为O(n),没有使用额外的空间
提交代码之后:
Runtime: 3 ms, faster than 100.00% of Java online submissions for Roman to Integer.
Memory Usage: 37.4 MB, less than 34.39% of Java online submissions for Roman to Integer.