JS中的罗马到整数为什么它只转换第一个字符

Roman to Integer in JS why it only convert the first character

我尝试解决Leedcode问题13,问题是给定一个罗马数字,将其转换为整数。(输入保证在1到3999的范围内。) 这是我下面的代码,我想知道为什么它只将罗马数字中的第一个字符转换为整数?

var romanToInt = function(s) {
  var result = 0;
  if (s == null) {
    result = 0;
  }
  var myMap = new Map();
  myMap.set('I', 1);
  myMap.set('V', 5);
  myMap.set('X', 10);
  myMap.set('L', 50);
  myMap.set('C', 100);
  myMap.set('D', 500);
  myMap.set('M', 1000);

  var len = s.length;
  for (var i = 0; i < len; i++) {
    if (myMap.get(s.charAt(i)) < myMap.get(s.charAt(i + 1))) {
      result -= myMap.get(s.charAt(i))
    } else {
      result += myMap.get(s.charAt(i))
    }
    return result;
  };
}

console.log(romanToInt('VI'));
console.log(romanToInt('V'));
console.log(romanToInt('VII'));

因为

return result;

循环结束一次。将其向下移动一行。如果你能正确格式化,你就不会犯这样的错误;)

const values = new Map([
  ['I', 1],
  ['V', 5],
  ['X', 10]
  /*....*/
]);

function romanToInt(string) {
  let result = 0,
    current, previous = 0;
  for (const char of string.split("").reverse()) {
    current = values.get(char);
    if (current >= previous) {
      result += current;
    } else {
      result -= current;
    }
    previous = current;
  }
  return result;
}

console.log(romanToInt('I'));
console.log(romanToInt('II'));
console.log(romanToInt('III'));
console.log(romanToInt('IV'));
console.log(romanToInt('V'));
console.log(romanToInt('VI'));
console.log(romanToInt('VII'));
console.log(romanToInt('VIII'));
console.log(romanToInt('IX'));
console.log(romanToInt('X'));
console.log(romanToInt('XI'));
console.log(romanToInt('XII'));
console.log(romanToInt('XIII'));
console.log(romanToInt('XIV'));
console.log(romanToInt('XV'));
console.log(romanToInt('XVI'));
console.log(romanToInt('XVII'));
console.log(romanToInt('XVIII'));
console.log(romanToInt('XIX'));
console.log(romanToInt('XX'));

因为你的return result;是内循环,只需将return result;移到外循环即可。

以下是您代码的简化(可读性)版本。

const myMap=new Map();
myMap.set('I', 1);
myMap.set('V', 5);
myMap.set('X', 10);
myMap.set('L', 50);
myMap.set('C', 100);
myMap.set('D', 500);
myMap.set('M', 1000);

var romanToInt = function(s) {
   var result=0;
   if(s){
     var s1=s.split('');
     s1.forEach(function(e,i){
          result += myMap.get(e) < myMap.get(s1[i+1]) ? -myMap.get(e) : myMap.get(e);  // used ternary oprator with '-' where required
     });
   }
   return result; //move it outside loop
}
console.log(romanToInt('IV'));
console.log(romanToInt('V'));
console.log(romanToInt('VII'));

也许你可以试试 :

function romanToInt(romanString) {
   if(typeof romanString !== 'string') return NaN;
   const romanRegExp = /^(?=[MDCLXVI])(M*)(?:(C)(?:(D)|(M))|(D?)(C{0,3}))(?:(X)(?:(L)|(C))|(L?)(X{0,3}))(?:(I)(?:(V)|(X))|(V?)(I{0,3}))$/i;
   let parts = romanString.match(romanRegExp);
   if(!parts) return NaN;
   let result = 0;
   [0, 1000, -100,500,1000,500,100, -10,50,100,50,10, -1,5,10,5,1].forEach(
      (weight, i) => result += weight * (parts[i] || '').length
   );
   return result;
}

console.log(romanToInt('IV'));
console.log(romanToInt('MMXIX'));

试试这个。它应该有效:


<div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false">
<div class="snippet-code">
<pre><code>function conversion(r) {
  const arr = r.split('');
  const val = {
    I: 1,
    V: 5,
    X: 10,
    L: 50,
    C: 100,
    D: 500,
    M: 1000,
  };

  let sum = 0;
  for (let i = 0; i < arr.length; i += 1) {
    if (val[arr[i]] < val[arr[i + 1]]) {
      sum += val[arr[i + 1]] - val[arr[i]];
      i += 1;
    } else {
      sum += val[arr[i]];
    }
  } return sum;
}
      
console.log(conversion("VIII"));
console.log(conversion("LXXIX"));
console.log(conversion("MCMXLIV"));

罗马整数的较短版本:

var romanToInt = (str) => {
  const roman = { I: 1, V: 5, X: 10, L: 50, C: 100, D: 500, M: 1000 };
  let num = 0;
  for (let i = 0; i < str.length; i++) {
    const curr = roman[str[i]];
    const next = roman[str[i + 1]];
    (curr < next) ? (num -= curr) : (num += curr);
  }
  return num;
};

console.log(romanToInt('IV'));
console.log(romanToInt('VIII'));
console.log(romanToInt('LXXIX'));
console.log(romanToInt('MCMXLIV'));


来自@Jin150Job

的另一个独特的解决方案

var romanToInt = (str) => {
  const roman = { I: 1, V: 5, X: 10, L: 50, C: 100, D: 500, M: 1000 };
  let num = 0;
  if (str.includes('CM')) num -= 200;
  if (str.includes('CD')) num -= 200;
  if (str.includes('XC')) num -= 20;
  if (str.includes('XL')) num -= 20;
  if (str.includes('IX')) num -= 2;
  if (str.includes('IV')) num -= 2;
  for (var i = 0; i < str.length; i++) {
    num += roman[str[i]];
  }
  return num;
};

console.log(romanToInt('IV'));
console.log(romanToInt('VIII'));
console.log(romanToInt('LXXIX'));
console.log(romanToInt('MCMXLIV'));

对此解决方案的一个很好且更可取的答案是:

  let roman = "XXI";
  const numeral = {I: 1, V: 5, X: 10, L: 50, C: 100, D: 500, M: 1000};
  let total = 0;
  let current, last = 0;
  roman.split("").reverse().forEach(e => {
    current = numeral[e];
    if (current >= last) {total += current;} else {total -= current;}
    last = current;
  });
  
  return total;

** 此解决方案适用于每个小于 3600 的罗马数字

function romanToInt(romeNumStr) {
    const romeMap = {I: 1, V: 5, X: 10, L: 50, C: 100, D: 500, M: 1000};
    let total = 0;
    for (let i=0; i<romeNumStr.length; i++) {
        const chVal = romeMap[romeNumStr[i]];
        let chNextVal
        if (i+1 < romeNumStr.length) {
            // There is more chars
            chNextVal = romeMap[romeNumStr[i+1]];
            if (chVal >= chNextVal) {
                total += chVal;
            } else {
                // Do reverse
                total += chNextVal-chVal
                i+=1
            }
        } else {
            // Last char
            total += chVal;
        }
    }
    return total
}

我的测试:

// TEST
romanToInt('MMMDXCIX')
=3599

这是另一种求罗马数字整数的方法

function romanToInt(romanNumber) {
   let currentValue = 0;
    let result = 0;
    const string = romanNumber.split('');
    const romanNumbers = {
      I: 1,
      V: 5,
      X: 10,
      L: 50,
      C: 100,
      D: 500,
      M: 1000,
    };
    let firstNum = romanNumbers[string[0].toUpperCase()];
    for (let char of string) {
      currentValue = romanNumbers[char.toUpperCase()];
      if (currentValue <= firstNum) {
        result += currentValue;
      } else {
        result = currentValue - result;
      }
    }
    console.log(`Roman: ${romanNumber}\nInteger: ${result} \n \n`);
    return result;
}

romanToInt('I');
romanToInt('IV');
romanToInt('VI');
romanToInt('IX');
romanToInt('X');
romanToInt('XI');
romanToInt('XII');
romanToInt('XL');
romanToInt('LV');
romanToInt('MMM');
romanToInt('MMC');
romanToInt('MMc');

这是一个使用 reduce

const romanNumerals = {
  I: 1,
  V: 5,
  X: 10,
  L: 50,
  C: 100,
  D: 500,
  M: 1000,
}

const convertToNumber = romanNumeral => {
  const romanDigits = romanNumeral.split('')

  return romanDigits.reduce(
    (acc, curr, index) =>
      romanNumerals[curr] < romanNumerals[romanDigits[index + 1]]
        ? acc - romanNumerals[curr]
        : acc + romanNumerals[curr],
    0
  )
}

console.log(convertToNumber('XXXIX'))
console.log(convertToNumber('XL'))
console.log(convertToNumber('MMXXI'))
console.log(convertToNumber('CLX'))
console.log(convertToNumber('DCCLXXXIX'))
console.log(convertToNumber('MCMXVIII'))
console.log(convertToNumber('MMMCMXCIX'))

首先我将 romanVal 声明为包含所有罗马符号值的对象,并在第二步将结果设置为零,然后 if (s === '') return; 检查用户输入是否为空然后它将 return result = 0,否则我使用输入并将其更改为数组并对其进行映射,此数组中的每个值更改为数字并推送到 inputval 数组,然后在此数组上循环以检查是否element[i] < or > element[i + 1] 从结果中添加或减去它。

var romanToInt = function (s) {
    let romanVal = { I: 1, V: 5, X: 10, L: 50, C: 100, D: 500, M: 1000 };
    let result = 0;
    if (s === '') return;
    let inputs = Array.of(...s);
    let inputsVal = [];
    inputs.map((e) => ((e = romanVal[e]), inputsVal.push(e)));
    for (let i = 0; i < inputsVal.length; i++) {
        inputsVal[i] < inputsVal[i + 1]
            ? (result -= inputsVal[i])
            : (result += inputsVal[i]);
    }
    return result;
};

romanToInt('III');

var romanToInt = function(s) {
    const map = new Map();
    map.set("I", 1);
    map.set("V", 5);
    map.set("X", 10);
    map.set("L", 50);
    map.set("C", 100);
    map.set("D", 500);
    map.set("M", 1000);
    map.set("IV", 4);
    map.set("IX", 9);
    map.set("XL", 40);
    map.set("XC", 90);
    map.set("CD", 400);
    map.set("CM", 900);
    if(s.length == 1){
        return map.get(s);
    }
    let sum = 0;
    for(let i = 0; i <s.length;){
        const dub = map.get(s[i]+s[i+1]);
        if(dub == undefined){
          sum += map.get(s[i]);
          i++;
        }else{
          sum += dub;
          i+=2;
        }
        
    }
    return sum;

};