题目描述
罗马数字包含以下七种字符: 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:
输入: 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.
解题思路
按照题目的描述,可以总结如下规则:
- 罗马数字由
I,V,X,L,C,D,M
构成; - 当小值在大值的左边,则减小值,如
IV=5-1=4
; - 当小值在大值的右边,则加小值,如
VI=5+1=6
; - 由上可知,右值永远为正,因此最后一位必然为正。
一言蔽之,把一个小值放在大值的左边,就是做减法,否则为加法。
在代码实现上,可以往后看多一位,对比当前位与后一位的大小关系,从而确定当前位是加还是减法。当没有下一位时,做加法即可。
代码
/**
* @param {string} s
* @return {number}
*/
const romanToInt = s => {
let map = new Map([['I', 1], ['V', 5], ['X', 10], ['L', 50], ['C', 100], ['D', 500], ['M', 1000]])
let res = 0;
for (let i = 0; i < s.length; i++) {
let left = map.get(s[i]);
let right = map.get(s[i + 1]);
res += left < right ? -left : left
}
return res
};
代码分析:
-
const romanToInt = s => {
:定义了一个名为romanToInt
的函数,它接受一个字符串参数s
,这个字符串是罗马数字的表示。 -
let map = new Map([['I', 1], ['V', 5], ['X', 10], ['L', 50], ['C', 100], ['D', 500], ['M', 1000]]);
:创建了一个映射(Map),将罗马数字的字母映射到它们对应的数值。 -
let res = 0;
:初始化一个变量res
,用于存储转换结果。 -
for (let i = 0; i < s.length; i++) {
:开始一个循环,遍历罗马数字字符串s
的每个字符。 -
let left = map.get(s[i]);
:获取当前字符s[i]
对应的数值,并将其存储在变量left
中。 -
let right = map.get(s[i + 1]);
:尝试获取下一个字符s[i + 1]
对应的数值,并将其存储在变量right
中。注意,如果i
是字符串的最后一个字符的索引,s[i + 1]
将不存在,这将导致错误。 -
res += left < right ? -left : left
:这是转换的核心逻辑。如果当前字符left
的数值小于下一个字符right
的数值(即left < right
),则表示当前字符的数值需要从结果中减去(因为罗马数字中较小的数值在较大的数值前表示减法)。否则,就正常将当前字符的数值加到结果中。 -
return res
:在遍历完所有字符后,返回计算得到的数值。
注意:
代码中,res += left < right ? -left : left;
由于在罗马数字中,较小的数值出现在较大的数值之前时表示减法,当 i
是字符串的最后一个索引时,s[i + 1]
将不存在,right
将是 undefined
,在 JavaScript 中,任何数值与 undefined
比较都会得到 false
,因此 left < right
将不成立,left
的值将被加到 res
。
因此,原始代码实际上可以正确处理字符串中的所有字符,包括最后一个字符,因为正确地处理了 right
为 undefined
的情况。