我的功能如下:
let romanToInt = romanNumber => {
if(typeof romanNumber !== 'string') throw new TypeError('Argument must be of type String');
const values = { 'I': 1, 'V': 5, 'X': 10, 'L': 50, 'C': 100, 'D': 500, 'M': 1000 };
let sum = 0;
romanNumber.split('').map(n => n.toUpperCase()).forEach(n => sum = (sum >= values[n]) ? sum + values[n] : values[n] - sum);
return sum;
}
console.log(romanToInt("MCMXCVI"));
我测试的大部分输入都是正确的,但罗马数字MCMXCVI
例如应该给我1996
,而不是2216
,这就是我得到的。
我发现了这一点,但我不确定如何实现:
您必须将数十,数百和数千个单独分开 项目。这意味着99是XCIX,90 + 9,但永远不应该写 作为IC。同样,999不能是IM而1999不能是MIM。
答案 0 :(得分:1)
根据您的问题,您需要迎合单独的项目。一种简单的方法是简单地将您的值设置得更大,并寻找多字符匹配。这是可能的,因为只有少数组合允许使用罗马数字。我把小提琴放在一起here
const values = {
'I': 1,
'V': 5,
'X': 10,
'L': 50,
'C': 100,
'D': 500,
'M': 1000,
'CM': 900,
'CD': 400,
'XC': 90,
'XL': 40,
'IX': 9,
'IV': 4
};
let sum = 0;
while(romanNumber.length > 0){
let piece = romanNumber.substring(0,2);
if(values[piece]){
sum += values[piece];
romanNumber = romanNumber.substring(2);
}else if(values[piece[0]]){
sum += values[piece[0]];
romanNumber = romanNumber.substring(1);
}
}
return sum;
答案 1 :(得分:0)
您不应该希望通过简单的映射来解决问题,因为在罗马数字中,数字的含义取决于上下文。我认为,许多情况可以用类似的东西来处理(而不是你的分裂和地图行):
var digits = romanNumber.split('');
var i = 0;
while (i < digits.length) {
if (i == digits.length - 1 || values[digits[i]] >= values[digits[i+1]]) {
sum += values[digits[i]];
i++;
}
else {
sum += values[digits[i+1]] - values[digits[i]];
i += 2;
}
}
但我不确定它是否适用于所有情况。最好看看它是如何在现成的库中实现的,也许是为其他语言实现的。例如,以下是Perl的实现:http://search.cpan.org/~chorny/Roman-1.24/lib/Roman.pm
答案 2 :(得分:0)
我认为你不能用单线程映射来实现,因为操作取决于彼此相邻的字符比较。但是,使用简单的for
循环:
var chars = romanNumber.split('');
var sum = values[chars[chars.length - 1]];
for (var i = chars.length - 2; i >= 0; i--) {
if (values[chars[i + 1]] <= values[chars[i]]) {
sum += values[chars[i]];
} else {
sum -= values[chars[i]];
}
}
当罗马数字的值小于其右边的数字时,你想要从总和中减去它而不是添加。