【Leetcode-简单-13】罗马数字转整数
题目描述:
来源:力扣(LeetCode)
链接: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, 即为 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
- 示例3:
输入:"IX"
输出:9
- 示例4:
输入: "LVIII"
输出:58
解释: L = 50, V= 5, III = 3.
- 示例5:
输入: "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 。
代码(python3)
方法①解析思路:(官方解法)
- 模拟 : 自己和右边比较,大了就加,小了就减
- 通常情况下,罗马数字中小的数字在大的数字的右边。若输入的字符串满足该情况,那么可以将每个字符视作一个单独的值,累加每个字符对应的数值即可。
例如: XXVII 可视作 : X+X+V+I+I=10+10+5+1+1=27。
- 若存在小的数字在大的数字的左边的情况,根据规则需要减去小的数字。对于这种情况,我们也可以将每个字符视作一个单独的值,若一个数字右侧的数字比它大,则将该数字的符号取反。
例如 \texttt{XIV}XIV 可视作 :X−I+V=10−1+5=14。
class Solution:
num_value = {
'I':1,
'V':5,
'X': 10,
'L': 50,
'C': 100,
'D': 500,
'M': 1000,
}
def romanToInt(self, s: str) -> int:
res = 0;
n = len(s);
for i ,ch in enumerate(s):
value = Solution.num_value[ch];
# 若一个数字右侧的数字比它大,则将该数字的符号取反
if i < n-1 and value < Solution.num_value[s[i+1]]:
res -= value;
else:
res += value;
return res
代码(c++)
解析思路:
class Solution {
private:
unordered_map<char, int> symbolValues = {
{
'I', 1},
{
'V', 5},
{
'X', 10},
{
'L', 50},
{
'C', 100},
{
'D', 500},
{
'M', 1000},
};
public:
int romanToInt(string s) {
int res = 0;
int n = s.length();
for (int i = 0; i < n; ++i){
int value = symbolValues[s[i]];
if (i < n-1 && value < symbolValues[s[i+1]]){
res -= value;
}
else{
res += value;
}
}
return res;
}
};
- 复杂度分析
时间复杂度:O(n),其中 n 是字符串 s 的长度。
空间复杂度:O(1)。
进阶:
- 大神版
解析思路:
class Solution:
def romanToInt(self, s: str) -> int:
d = {
'I':1, 'IV':3, 'V':5, 'IX':8, 'X':10, 'XL':30, 'L':50, 'XC':80, 'C':100, 'CD':300, 'D':500, 'CM':800, 'M':1000}
return sum(d.get(s[max(i-1, 0):i+1], d[n]) for i, n in enumerate(s))
-
思路:
-
构建一个字典记录所有罗马数字子串,注意长度为2的子串记录的值是(实际值 - 子串内左边罗马数字代表的数值)
-
这样一来,遍历整个 s 的时候判断当前位置和前一个位置的两个字符组成的字符串是否在字典内,如果在就记录值,不在就说明当前位置不存在小数字在前面的情况,直接记录当前位置字符对应值
-
示例:遍历经过 IV的时候先记录 I的对应值 1再往前移动一步记录 IV 的值 3,加起来正好是 IV 的真实值 4。max 函数在这里是为了防止遍历第一个字符的时候出现 [-1:0]的情况。
-
Python 中我们使用字典 {key : value} 来初始化哈希表
-
通过 key 查找 value 的时间复杂度为 O(1)
-
这题题解中的 d 就是一个字典,其中 get(key, default) 函数可以通过 key 从 d 中找出对应的值,如果 key 不存在则返回默认值 default
作者:QQqun902025048
链接:https://leetcode-cn.com/problems/roman-to-integer/solution/2-xing-python-on-by-knifezhu/