难度:简单
通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做 IIII,而是 IV。这个特殊的规则只适用于以下六种情况:
I 可以放在 V (5) 和 X (10) 的左边,来表示 4 和 9。
X 可以放在 L (50) 和 C (100) 的左边,来表示 40 和 90。
C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900。
给定一个罗马数字,将其转换成整数。输入确保在 1 到 3999 的范围内。
此题的难点在于如何去处理以上特殊的规则。
方法一:(遍历法)
也是我们最容易想到方法,看到这种类似于列表一一对应的问题,第一想法就是用switch…case…去把罗马字母和数值对应起来,然后再用if语句去处理特殊的情况。
- 定义一个获取罗马字符对应数字的静态方法getValue(char c),使用switch来获取字符对应的数字。
- 遍历从第一个字符开始,比较当前字符与后一个字符对应数字大小,大于等于则加上当前字符所对应的数值,否则减。最后一个字符也同样是加。
知识盲点:
-
charAt函数
charAt(int index)方法是一个能够用来检索特定索引下的字符实例的方法。
charAt()方法返回指定索引位置的char值。索引范围为0~length()-1,如: str.charAt(0)检索str中的第一个字符,str.charAt(str.length()-1)检索最后一个字符。
Java实例:
public class Test { public static void main(String[] args) { String s = "123456"; for(int index=0;index<s.length();index++)//将字符串中的字符逐个按行输出 { System.out.print(s.charAt(index)); } } }
下面贴出该方法的解题代码:
class Solution {
public static 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:
throw new IllegalArgumentException("Illegal character");
}
}
public int romanToInt(String s) {
int len = s.length();
int num = 0;
for(int i=0;i<len;i++){
if(i==len-1 || getValue(s.charAt(i)) >= getValue(s.charAt(i+1)))
num += getValue(s.charAt(i));
else
num -= getValue(s.charAt(i));
}
return num;
}
}
遇到的问题:
-
在写default的时候没有使用了syso输出了一个语句,但该函数的返回值类型为int而不是void,于是改成了throw函数抛出异常。
-
在比较前一项与后一项的数值的时候,没有考虑循环范围是0-length-1,直接就比位置i与位置i+1的大小,但是i+1会越界,于是将最后一位单独拎出来计算,if条件里两项判断,或连接。
方法二:(Hash表,字母组合求解法)
- 首先将所有的组合可能性列出并添加到哈希表中
- 然后对字符串进行遍历,由于组合只有两种,一种是1个字符,一种是2个字符,其中2个字符优先于1个字符
- 先判断两个字符的组合在哈希表中是否存在,存在则将值取出加到结果 ans 中,并向后移2个字符。不存在则将判断当前1个字符是否存在,存在则将值取出加到结果ans中,并向后移1个字符
- 遍历结束返回结果 ans
回顾:
- map.containsKey(Object key):判断Map集合对象中是否包含指定的键名
- map.get(Object key):输入键名,返回键值(这里的键名是字母组合,键值是对应数字)
下面贴出该方法的解题代码:
class Solution {
public int romanToInt(String s) {
Map<String, Integer> map = new HashMap<>();
map.put("I", 1);
map.put("IV", 4);
map.put("V", 5);
map.put("IX", 9);
map.put("X", 10);
map.put("XL", 40);
map.put("L", 50);
map.put("XC", 90);
map.put("C", 100);
map.put("CD", 400);
map.put("D", 500);
map.put("CM", 900);
map.put("M", 1000);
int ans = 0;
for(int i = 0;i < s.length();) {
//先进行2字符判断
if(i + 1 < s.length() && map.containsKey(s.substring(i, i+2))) {
ans += map.get(s.substring(i, i+2));
i += 2;
}
//不是2字符情况再加1字符对应值
else {
ans += map.get(s.substring(i, i+1));
i ++;
}
}
return ans;
}
}
作者:guanpengchn
链接:https://leetcode-cn.com/problems/roman-to-integer/solution/hua-jie-suan-fa-13-luo-ma-shu-zi-zhuan-zheng-shu-b/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
通过此题我还发现,hashmap比switch慢一倍……
再用神奇的Python写一下吧,思路还是以上思路。
class Solution:
def romanToInt(self, s: str) -> int:
mapping = {'I':1,'V':5,'X':10,'L':50,'C':100,'D':500,'M':1000}
result = 0
for i in range(len(s)-1):
if mapping[s[i]] < mapping[s[i + 1]]:
result -= mapping[s[i]]
else:
result += mapping[s[i]]
return result+mapping[s[-1]]
#众所周知,s[-1]表示最后一个字符,相当于s[len(s)-1]