一、题目描述
1.题目内容
罗马数字包含以下七种字符: 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。
给定一个罗马数字,将其转换成整数
原题链接:https://leetcode.cn/problems/roman-to-integer/
与此相反,LeetCode12:整数转罗马数字,可参考https://blog.csdn.net/qq_43665602/article/details/127318353
2.样例
二、解决方案
初步想法:
通过观察发现:
正常情况:一个基础罗马字符A对应一个数值NUM,比如I=1,V=5。对于连续字符串AB,此时NUM=B-A<=0,比如字符串VI,此时I-V=-4<0;
特殊情况:特殊情况下两个罗马字符AB构成一个数值NUM,且NUM=B-A>0。比如IV=V-I=4>0;
由此得到解题步骤:
- 1.将基础罗马数字及其对应的数值构造映射关系存储;
- 2.创建两个指针i,j分别指向两个相邻的字符,初始化i=0,j=1;
- 3.比较字符串s,s[j]-s[i]对应的数值是否大于0,如果大于0,说明此时相邻两个字符可能构成特殊情况,左面字符小于右面字符:若为特殊情况,则此时i和j同时向右移动2个距离,否则说明此时i所指向的字符为基础字符,此时i,j向右移动1个距离;
- 4.反之,如果s[j]-s[i]<=0,说明此时i所指向的字符为基础字符,此时i,j向右移动1个距离;
在代码实现时,有两个需要注意的点:
- (1)除了6种特殊情况,其他的都是正常情况:通过判断s[j]-s[i]%100=4或s[j]-s[i]%100=9等条件是否满足,确定特殊情况;
- (2)因为如果遇到特殊情况,指针i和j同时向右移动两个位置,那么当传入字符串最后两个字符不构成特殊情况时,j会指向s.length的位置,也就是发生了数组越界,出现空指针异常。为了避免这种情况发生,需要在每次迭代开始时,判断一下j是否越界,如果越界则说明字符串最后的字符属于正常情况,直接处理i所指向的字符即可(如例2);
举个例子:
例1:
例2:
1.Java代码
Java实现时,可以构建映射关系的数据结构,当属HashMap。
import java.util.HashMap;
import java.util.Map;
public class RomanToInt {
public static int romanToInt(String s) {
int num=0;
String[] romanKey=new String[]{"I","V","X","L","C","D","M"};
int[] intValue=new int[]{1,5,10,50,100,500,1000};
Map<String,Integer> romanToInt=new HashMap<String,Integer>();
for(int k=0;k<romanKey.length;k++) {
romanToInt.put(romanKey[k],intValue[k]);
}
// System.out.println(romanToInt);
int i=0;
int j=1;
while (i<s.length()){
int difference=0; // 计算相邻字符对应数值的差值
if(j<s.length()) {
difference = romanToInt.get(s.charAt(j) + "") - romanToInt.get(s.charAt(i) + "");
}else { // 当j移动到最后一次判断时有可能越界,此处用于避免空指针异常
difference=romanToInt.get(s.charAt(i) + "");
}
// 判断特殊情况
if(difference>0&&(difference%100==4||difference%100==9||difference%100==40||difference%100==90||difference%100==0)){
// 如果符合六种特殊情况,则更新num,i和j同时向右移动2个距离;
num+=difference;
i+=2;
j+=2;
}else{ // 处理正常情况
num+=romanToInt.get(s.charAt(i)+"");
i+=1;
j+=1;
}
}
return num;
}
public static void main(String[] args) {
// String s = "MCMXCIV";
String s = "III";
// String s = "LVIII";
// String s = "IX";
// String s = "IV";
System.out.println(romanToInt(s));
}
}
提交结果一发入魂:
2.Python代码
Python实现时,可以构建映射关系的数据结构,当属字典dict。
'''
LeetCode13:罗马数字转整数
'''
def roman_to_int(s):
num = 0
romanKey = ["I", "V", "X", "L", "C", "D", "M"]
intValue = [1, 5, 10, 50, 100, 500, 1000]
romanToInt ={}
for k in range(0,len(romanKey)):
romanToInt[romanKey[k]]=intValue[k]
i=0
j=1
while i<len(s):
if j<len(s):
difference=romanToInt[s[j]]-romanToInt[s[i]]
else:
difference = romanToInt[s[i]]
if difference>0 and (difference%100==4 or difference%100==9 or difference%100==40 or
difference%100==90 or difference%100==0 ):
num+=difference
i+=2
j+=2
else:
num+=romanToInt[s[i]]
i+=1
j+=1
return num
if __name__=='__main__':
# s = "MCMXCIV"
# s = "III"
s = "LVIII"
# s = "IX"
# s = "IV"
print(roman_to_int(s))
提交结果: