Integer to Roman

zoovely·2024년 5월 1일
0
post-thumbnail

💬 문제

[문제 링크]

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

의 규칙에 기반하여 주어진 정수를 로마자 문자열로 변환하여 반환
단,IV = 4 IX = 9 XL = 40 XC = 90 CD = 400 CM = 900이라는 예외가 있음

✍️ 나의 풀이

/**
 * @param {number} num
 * @return {string}
 */
var intToRoman = function(num) {
    const symbols = ['I', 'V', 'X', 'L', 'C', 'D', 'M'];
    const string = num.toString();

    let res = '';
    let idx = 0;
    for (let i = string.length - 1; i >= 0; i--) {
        const div = Math.floor(string[i] / 5);
        const remain = string[i] % 5;
        if (remain === 4)
            res = div === 1 ? symbols[idx] + symbols[idx + 2] + res 
            : symbols[idx] + symbols[idx + 1] + res;
        else if (div === 1)
            res = symbols[idx + 1].repeat(div) + symbols[idx].repeat(remain) + res;
        else
            res = symbols[idx].repeat(remain) + res;
        idx += 2;
    }

    return res;
};

문자열로 변환한 num을 뒤에서 부터 (일의 자리에서 부터) 순환하며 계산
1000의 자리부터 시작하면 한 자리 정수가 주어졌을 때 불필요한 연산이 생긴다고 생각했음...
각 자리마다 5로 나눈 몫과 나머지를 이용하여 몫 * 5배수 문자 + 나머지 * 1배수 문자를 결과값에 추가
뒤에서부터 시작했기 때문에 이전 문자열은 마지막에 붙여줌
그 중 나머지가 4인 것은 4혹은 9이기 때문에 예외 규칙에 따라 문자열 생성
이후 idx + 2하여 다음 1배수 문자로 이동
마지막 M 다음의 5의 배수는 없기 때문에 idx + 1 접근 시 참조 에러가 나지 않도록 몫이 1일 때만 접근하도록 조건문을 붙임 (주어지는 정수가 3999까지라서 이렇게 막아도 괜찮았음)

📌 결과

Accepted
Runtime 127ms (Beats 21.92%)
Memory 54.76MB (Beats 57.20%)

📚 러닝 포인트

이전 문제의 반대 버전이어서 저번처럼 Map을 활용할까? 했는데 앞서 말했듯이 앞자리부터 계산하고 싶지 않았기 때문에 숫자를 저장해둘 필요가 없어서 배열을 사용했다. 그런데 생각보다 실행 시간이 오래 걸려서 의미는 없었지만... toString으로 바꾸고 여러 조건에서 이것저것 붙이다 보니까 느려진 것 같다. 그래도 혼자 만든 것 치고는 꽤 만족해서 다른 사람들 거를 보니 훨씬 간단하더라. 역시나 맵을 사용했고, 4와 9의 예외 규칙은 어떻게 해야되지 생각을 많이 했었는데 그냥 그거 마저 XL : 50 이렇게 넣어 놓고 높은 숫자부터 쭉 나눈 몫을 문자열에 추가하는 방식을 대부분 사용했다. 내 것이 틀린 알고리즘은 아니지만 좀 더 간단하게 표현할 수 있도록 생각을 더 하는 사람이 되자.

profile
나도 할 수 있을까?

0개의 댓글