본문 바로가기
D.evelop [CS]/Algorithm

[Algorithm 009] JS - romanToNum

by Danne 2021. 9. 27.

Q. 로마자에서 숫자로 바꾸기

  • 1~3999 사이의 로마자 s를 인자로 주면 그에 해당하는 숫자를 반환
Symbol Value
I 1
V 5
X 10
L 50
C 100
D 500
M 1000

 

  • 로마자를 숫자로 읽는 방법은 로마자를 왼쪽부터 차례대로 더하면 됨
III = 3
XII = 12
XXVII = 27

 

  • 그런데 4를 표현할 때는 IIII가 아니라 IV 
  • 뒤의 숫자에서 앞의 숫자를 빼주는 형식
    • 예) 9는 IX
IV, X앞에 와서 4, 9 
X는 L, C앞에 와서 40, 90 
C는 D, M앞에 와서 400, 900

 

 

 

처음 접근 법

function romanToNum(s) {
  const symbolArr= ['I', 'V', 'X', 'L', 'C', 'D', 'M'];
  const numValue = [1, 5, 10, 50, 100, 500, 1000];
  const symbol = s.split('');
   
  for (i = 0; i < symbolArr.length; i++){
    symbolArr[i] = numValue[i]
  }
}

romanToNum('XXVII')
1. 각 값을 배열로 만들어, 해당 index값을 기준으로 로마자에 값을 부여
2. 전달받은 '로마자'를 '로마자 배열(symbolArr)'에 매칭하여, 각 값을 더한 값을 반환
3. 4, 9, 40, 90, 400, 900의 예외 케이스 설정

처음엔 위와 같은 생각을로 접근했다.

그러나 2번부터 막힘🤯 (시간 초과)

 

 

 

A.  최종 답 (+네비게이터님의 피드백)

📍TIP
 객체 사용
 ES6의 Spread Operator(스프레드 연산자)

 

function romanToNum(s) {
 let obj = {
    I:1,
    V:5,
    X:10,
    L:50,
    C:100,
    D:500,
    M:1000
 }
 const arr = [...s];
 let sum = 0;

 for(i = 0; i < arr.length; i++ ){
   let a = obj[arr[i]]
   let b = obj[arr[i+1]]
   if(a < b){
     sum -= a
   }else{
     sum = sum + a
   }
 }

 return sum
}

romanToNum('XXVII')   // 27
romanToNum('IX')      // 9
romanToNum('XC')      // 90

 

 

1. 객체(object) 사용

  • 'a의 값은 x', 'b의 값은 y'...와 같은 형식의 조건은 key와  value값으로 묶어 객체로 사용하면 유용하다.
let obj = {
    I:1,
    V:5,
    X:10,
    L:50,
    C:100,
    D:500,
    M:1000
 }

 

 

2. 예외 규칙 찾기

  • 일반 케이스와 예외 케이스의 차이를 생각하고, 예외 규칙 구하기
👉 일반 케이스
3은 III = 1 + 1 + 1
5는 V = 5
6은 VI = 5 + 1
60은 XL = 50 + 10

로마자로 기준 : 뒤의 수가 작은 수 ( 앞의 값 > 뒤의 )
아라비아 숫자 기준 : 앞의 수에 뒤의 수를 더함 ( 앞의 + 뒤의 )

👉 예외 케이스
4는 IV = -1 + 5
9는 IX = -1 + 10
40은 XL = -10 + 50
90은 XC = -10 + 100 

로마자로 기준 : 작은 수, 뒤의 수가 큰 수 ( 앞의 < 뒤의 )
아라비아 숫자 기준 : 뒤의 수에서 앞의 수를 뺌 (뒤의 - 앞의 )

 

  • if 문을 사용해 예외 케이스(앞의 값 < 뒤의 값)일 경우
    뒤의 값에서 앞의 값을 빼는 연산 적용
const arr = [...s];
let sum = 0;

for(i = 0; i < arr.length; i++ ){
   let a = obj[arr[i]]
   let b = obj[arr[i+1]]
   if(a < b){
     sum -= a
   }else{
     sum = sum + a
   }
 }

 

 

❗️헷갈렸던 부분 확실히 알고 넘어가기 

 

const arr = [...s];
let sum = 0;

for(i = 0; i < arr.length; i++ ){
   let a = obj[arr[i]]
   let b = obj[arr[i+1]]
   if(a < b){
     sum -= a
   }
   sum = sum + a
 }

처음엔  sum = sum + a 를 기본으로 하고,

예외의 경우에만 sum -= a를 수행하게 위해 if 조건문만 작성했었다.

하지만 예외 케이스로 계산돼야 할 값이 일반 케이스로 연산된 값으로 출력됐다.

romanToNum('XXVII') // 27
romanToNum('IX')    // 10   : 9가 나와야 함
romanToNum('XC')    // 100  : 90이 나와야 함

 

console.log 폭풍 찍기⌨️

 

 

✔️  if을 잘못 활용했다.

예를 들어 IX값이 주어졌을 때,

if 조건을 만족한다. sum -= a실행.
즉, 10-1 = 9값이 나온다.

그런데 밑의  sum = sum + a도 실행 해버리면서
도로 1이 더해지는 것
10 - 1 = 9
9 + 1 = 10

 

A연산 or B연산이 되어야하는데, A연산 and B연산을 만들어 버린 것이다.

고로 이럴 땐 if else 문 또는 삼항연산자로 작성해줘야한다.

// if else 문
if(a < b){
	sum -= a
}else{
	sum = sum + a
}

// 삼항연산자
a < b ? sum -= a : sum = sum + a

 

 

확인하고 보니 당연한 문제였는데, 꼬아서 생각하다 돌아가버렸다.

 

 

 

3. Spread Operator(스프레드 연산자) MDN명세

const arr = 'abcdef';

console.log(arr.split(''));    // [ 'a', 'b', 'c', 'd' ]

console.log([...arr]);         // [ 'a', 'b', 'c', 'd' ]
console.log([...arr,'last']);  // [ 'a', 'b', 'c', 'd', 'last' ]
console.log(['first',...arr]); // [ 'first', 'a', 'b', 'c', 'd' ]

 

 

 

 

반응형

'D.evelop [CS] > Algorithm' 카테고리의 다른 글

[Algorithm 011] JS - topK  (0) 2021.10.03
[Algorithm 010] JS - moreThanHalf  (0) 2021.10.02
[Algorithm 008] JS - 1주차 test 다시 풀기  (0) 2021.09.23
[Algorithm 007] JS - sameReverse  (0) 2021.09.16
[Algorithm 006] JS - reverse  (0) 2021.09.14

댓글