본문 바로가기

❓ 문제

Roman numerals are represented by seven different symbols: I, V, X, L, C, D and M.

 

로마 숫자는 I, V, X, L, C, D, M의 7가지 기호로 표시된다.

Symbol       Value
I             1
V             5
X             10
L             50
C             100
D             500
M             1000

For example, 2 is written as II in Roman numeral, just two one's added together. 12 is written as XII, which is simply X + II. The number 27 is written as XXVII, which is XX + V + II.

Roman numerals are usually written largest to smallest from left to right. However, the numeral for four is not IIII. Instead, the number four is written as IV. Because the one is before the five we subtract it making four. The same principle applies to the number nine, which is written as IX. There are six instances where subtraction is used:

  • I can be placed before V (5) and X (10) to make 4 and 9. 
  • X can be placed before L (50) and C (100) to make 40 and 90. 
  • C can be placed before D (500) and M (1000) to make 400 and 900.

Given a roman numeral, convert it to an integer.

 

예를 들어 2는 로마 숫자로 II로 표기되며 2개만 더하면 된다. 12는 단순히 X + II인 XII이다. 숫자 27은 XXVII로 표기되며 XX + V + II이다.

로마 숫자는 일반적으로 왼쪽에서 오른쪽으로 큰 거에서 작은 것으로 표기한다. 그러나 숫자 4는 IIII이 아니다. 그 대신에 숫자 4는 IV로 표기된다. 왜냐하면 1은 5보다 앞이기 때문에 빼서 4가 된다. 이 원리는 IX로 표기하는 숫자 9에도 적용된다. 빼기에 사용되는 경우 6가지 :

  • I를 V(5)와 X(10) 앞에 놓아 4와 9를 만들 수 있다.
  • L(50)과 C(100) 앞에 X를 붙여 40과 90을 만들 수 있다.
  • C는 D(500)와 M(1000) 앞에 위치하여 400과 900을 만들 수 있다.

로마 숫자가 주어지면 그것을 정수로 변환해보자.

 

Example 1:

Input: s = "III"
Output: 3
Explanation: III = 3.

Example 2:

Input: s = "LVIII"
Output: 58
Explanation: L = 50, V= 5, III = 3.

Example 3:

Input: s = "MCMXCIV"
Output: 1994
Explanation: M = 1000, CM = 900, XC = 90 and IV = 4.

 

❗ 내 풀이

내 생각

  • 문자를 숫자로 치한해야 한다.
  • 뒤에 수가 더 큰 지 파악 후 숫자 4나 9 같은 경우를 계산해줘야 한다.
/**
 * @param {string} s
 * @return {number}
 */
var romanToInt = function(s) {
    let sum = 0;
    
    for(let i = 0; i < s.length ; i++) {
        let num1 = getIntToRoman(s[i]);
        let num2 = getIntToRoman(s[i + 1]);
        if(num1 < num2) {
            sum += num2 - num1;
            i++;
        } else {
            sum += num1;
        }
    }
    
    return sum;
};


function getIntToRoman(romanChar) {
    switch(romanChar) {
        case 'I':
            return 1;
        case 'V':
            return 5;
        case 'X':
            return 10;
        case 'L':
            return 50;
        case 'C':
            return 100;
        case 'D':
            return 500;
        case 'M':
            return 1000;
        default:
            return 0;
    }
}
Runtime: 180 ms
Memory Usage: 46.8 MB

❗ Runtime이 가장 빨랐던 답변과 비교

/**
 * @param {string} s
 * @return {number}
 */
var romanToInt = function(s) {
    //make object map to store for each Letter value
    const letterVal = {
        I: 1,
        V: 5,
        X: 10,
        L: 50,
        C: 100,
        D: 500,
        M: 1000,
    };
    
    let total = 0;
    for (let i = 0; i < s.length; i++) {
        let currentVal = letterVal[s.charAt(i)]; 
        let nextVal = letterVal[s.charAt(i + 1)];
        if (nextVal) {
        if (currentVal >=  nextVal) {
             total += currentVal;
         } else {
                total += (nextVal - currentVal);
                i++;
         }
       } else {
            total += currentVal;
        }
    }
    return total;
};

함수를 만들어서 로마 숫자를 정수로 바꾼 것과 달리 enum을 사용하여 값을 구하였다.

(함수로 만들었기에 default로 0을 주어 계산하지 못하게 하였지만 열거형이기에 이는 불가능하여 if문을 사용하였다.)

 

❗ Memory 사용이 가장 적었던 답변과 비교

/**
 * @param {string} s
 * @return {number}
 */
var romanToInt = function (s) {
let obj = {
    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++) {
    if (obj[s[i]] < obj[s[i + 1]]) {
      res -= obj[s[i]];
      continue;
    }
    res += obj[s[i]];
  }
  return res;
};

Runtime이 가장 빨랐던 답변과 동일하게 enum을 사용하였다.

다른 점은 모든 값을 더하고 다음 값이 이전보다 크면 빼주는 형태로 간단하게 작성하였다.

 

LeetCode를 Detail을 보고 파악한 것이지만 실제로 Runtime이 엄청 빠르거나 메모리가 적지 않을 수도 있다.

💡 개선방안 적용 후 내 풀이

  • 함수를 사용하는 것보다 enum을 사용하기
  • 변수를 선언할 때는 num1, num2처럼 네이밍을 알 수 없게 짓지 말고 curVal, nextVal 등과 같이 뜻을 알 수 있게 작성하기
/**
 * @param {string} s
 * @return {number}
 */
var romanToInt = function (s) {
  const letterVal = {
    I: 1,
    V: 5,
    X: 10,
    L: 50,
    C: 100,
    D: 500,
    M: 1000,
  };

  let total = 0;
  for (let i = 0; i < s.length; i++) {
    if (letterVal[s[i + 1]] && letterVal[s[i]] < letterVal[s[i + 1]]) {
      total -= letterVal[s[i]];
    } else {
      total += letterVal[s[i]];   
    }
  }
  return total;
};
Runtime: 120ms
Memory Usage: 47.6 MB

🚩 Detail

개발의 각궁

Spring | Spring MVC | Spring Boot | Spring Security | Mysql | Oracle | PostgreSQL | Mybatis | JPA | Angular.js | Vue.js | Nuxt.js | React.js | TypeScript | JSP | Frontend | Backend