题目:罗马数字转整数
- 题号:13
- 难度:简单
- https://leetcode-cn.com/problems/roman-to-integer/
罗马数字包含以下七种字符: 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
, 即为X + X + 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:
输入: s = "III"
输出: 3
示例 2:
输入: s = "IV"
输出: 4
示例 3:
输入: s = "IX"
输出: 9
示例 4:
输入: s = "LVIII"
输出: 58
解释: L = 50, V= 5, III = 3.
示例 5:
输入: s = "MCMXCIV"
输出: 1994
解释: M = 1000, CM = 900, XC = 90, IV = 4.
提示:
- 1 <= s.length <= 15
s
仅含字符('I', 'V', 'X', 'L', 'C', 'D', 'M')
- 题目数据保证
s
是一个有效的罗马数字,且表示整数在范围[1, 3999]
内 - 题目所给测试用例皆符合罗马数字书写规则,不会出现跨位等情况。
- IL 和 IM 这样的例子并不符合题目要求,49 应该写作 XLIX,999 应该写作 CMXCIX 。
- 关于罗马数字的详尽书写规则,可以参考 罗马数字 - Mathematics 。
实现
第一种:直接法
根据“罗马数字中小的数字在大的数字的右边”以及六种特殊情况的规则直接去写代码。
public class Solution
{
public int RomanToInt(string s)
{
int result = 0;
int count = s.Length;
int i = 0;
while (i < count)
{
char c = s[i];
int move = 0;
switch (c)
{
case 'I':
result += PreI(i, s, ref move);
break;
case 'V':
result += 5;
move = 1;
break;
case 'X':
result += PreX(i, s, ref move);
break;
case 'L':
result += 50;
move = 1;
break;
case 'C':
result += PreC(i, s, ref move);
break;
case 'D':
result += 500;
move = 1;
break;
case 'M':
result += 1000;
move = 1;
break;
}
i += move;
}
return result;
}
private int PreI(int index, string s, ref int move)
{
//I 1
//IV 4
//IX 9
//II 2
int result = 0;
int count = s.Length;
if (index + 1 < count)
{
char c = s[index + 1];
switch (c)
{
case 'V':
result = 4;
move = 2;
break;
case 'X':
result = 9;
move = 2;
break;
case 'I':
result = 2;
move = 2;
break;
}
}
else
{
result = 1;
move = 1;
}
return result;
}
private int PreX(int index, string s, ref int move)
{
//X 10
//XL 40
//XC 90
int result = 0;
int count = s.Length;
if (index + 1 < count)
{
char c = s[index + 1];
switch (c)
{
case 'L':
result = 40;
move = 2;
break;
case 'C':
result = 90;
move = 2;
break;
default:
result = 10;
move = 1;
break;
}
}
else
{
result = 10;
move = 1;
}
return result;
}
private int PreC(int index, string s, ref int move)
{
//C 100
//CD 400
//CM 900
int result = 0;
int count = s.Length;
if (index + 1 < count)
{
char c = s[index + 1];
switch (c)
{
case 'D':
result = 400;
move = 2;
break;
case 'M':
result = 900;
move = 2;
break;
default:
result = 100;
move = 1;
break;
}
}
else
{
result = 100;
move = 1;
}
return result;
}
}
第二种:利用字典的方法
思路:利用字典的方式
把字典当作一个存储容器,key
存储罗马字符的所有组合,value
存储该组合代表的值。
每次取一个字符,判断这个字符之后是否还有字符。如果有,则判断这两个字符是否在字典中,如果存在则取值。否则,按照一个字符去取值即可。
C# 语言
public class Solution
{
public int RomanToInt(string s)
{
Dictionary<string, int> dic = new Dictionary<string, int>();
dic.Add("I", 1);
dic.Add("II", 2);
dic.Add("IV", 4);
dic.Add("IX", 9);
dic.Add("X", 10);
dic.Add("XL", 40);
dic.Add("XC", 90);
dic.Add("C", 100);
dic.Add("CD", 400);
dic.Add("CM", 900);
dic.Add("V", 5);
dic.Add("L", 50);
dic.Add("D", 500);
dic.Add("M", 1000);
int result = 0;
int count = s.Length;
int i = 0;
while (i < count)
{
char c = s[i];
if (i + 1 < count && dic.ContainsKey(s.Substring(i, 2)))
{
result += dic[s.Substring(i, 2)];
i += 2;
}
else
{
result += dic[c.ToString()];
i += 1;
}
}
return result;
}
}
Python 语言
class Solution(object):
def romanToInt(self, s):
"""
:type s: str
:rtype: int
"""
dic = {"I": 1, "II": 2, "IV": 4, "IX": 9,
"X": 10, "XL": 40, "XC": 90,
"C": 100, "CD": 400, "CM": 900,
"V": 5, "L": 50, "D": 500, "M": 1000}
result = 0
count = len(s)
i = 0
while i < count:
c = s[i]
if i + 1 < count and s[i:i + 2] in dic:
result += dic[s[i:i + 2]]
i += 2
else:
result += dic[c]
i += 1
return result