본 캠프/JavaScript 문법 종합반

JavaScript 문법 종합반 3주차. (3)

Iruka913 2024. 10. 23. 21:01

신이 나는 알고리즘 풀이 시간. 

function solution(n, m) {
    // 최대공약수 (GCD) 계산
    const gcd = (a, b) => {
        while (b) {
            [a, b] = [b, a % b];
        }
        return a;
    };

    // 최소공배수 (LCM) 계산
    const lcm = (a, b) => (a * b) / gcd(a, b);

    const gcdValue = gcd(n, m);
    const lcmValue = lcm(n, m);

    console.log([gcdValue, lcmValue]);
}

 

오늘은 지난 번 풀지 못 했던 알고리즘을 이해하는 시간을 가져보도록 하자. 

 

(복습)

 

while문이란? 

 

로드 런너와 코요테.

 

while은 ()안의 조건이 false가 될 때까지 반복한다. 

 

로드 런너는 모서리가 아닐 시에 전력 질주를 반복하는 알고리즘을 갖고 있다. 그래서 낭떠러지를 만나자마자 끼이이익! 하고 멈춰버린다. 

 

코요테는 do - while 문을 사용하고 있다. 조건에 따라 반복을 계속 할 지를 결정하는 건 마찬가지지만, 무조건 중괄호 블럭을 한 번 실행한다. 그래서 코요테는 낭떠러지를 만나든 말든 '일단 달린다.' 

 

그렇다... 코요테는 낭떠러지를 만나도 한 번은 실행되는 run 문 때문에 떨어지고 마는 것이다. 

 

그럼 위의 예시를 보자. 

 

    const gcd = (a, b) => {
        while (b) {
            [a, b] = [b, a % b];
        }
        return a;
    };

 

이런 식으로 while 안에 숫자가 들어가 있으면, b가 0이 될 때까지 반복하는 로직을 지닌다. 

 

아래 부분은 구조 분해 할당을 사용하고 있다.

 

a라는 매개 변수, b라는 매개 변수를 가지는 배열을 생성하고, 서로 계속 순서를 바꿔가며 '유클리드 호제법'에 따라 최대공약수를 구하고 있다. 그리고 최종적으로 계산이 끝난 최대공약수 a를 return 하고 있다. 

 

    // 최소공배수 (LCM) 계산
    const lcm = (a, b) => (a * b) / gcd(a, b);

 

최소공배수를 구하는 공식은 두 수를 곱한 값에다가 두 수의 최대공약수를 나누는 것이다. 그래서 최대공약수를 구하면 최소공배수도 쉽게 구할 수 있다. 

 

※ 최대공약수, 최소공배수, 간단한 소인수분해 정도는 구현할 줄 알아야 앞으로의 코테가 편해질 거 같다. 유클리드 호제법을 통한 공약수 구하기는 몰라도, 최소공배수의 공식은 외워두자. 

 

자연수 n이 매개변수로 주어집니다. n을 3진법 상에서 앞뒤로 뒤집은 후, 이를 다시 10진법으로 표현한 수를 return 하도록 solution 함수를 완성해주세요.

function solution(n) {
    let answer = 0;
    let answerArray = [];
    let i = n;
    while (i > 0) {
        answerArray.push(i % 3);
        i = Math.floor(i / 3);
    }
    for (let index = 0; index < answerArray.length; index++) {
            answer += answerArray[index] * 3 ** (answerArray.length - index - 1)
    }
    return answer;
}

 

정답.

내가 간과했던 점들.

1. 3진법으로의 전환. 

 

코드는 맞게 썼는데 push하는 순서가 잘못되었음. 그래서 자릿수가 하나 덜 출력되는 문제 발생. 

push의 순서에도 유념해야함. 

 

2. 뒤집기의 과정 불필요. 

출력된 배열 자체가 이미 뒤집어진 상태기 때문에 별도의 뒤집기 과정이 필요가 없음. push를 통해 하나씩 들어가기 때문. 

 

3. 거듭 제곱의 수식. 

 

거듭제곱은 ^ 보단 자바스크립트에서는 **를 이용함. 

 

-> 다시 풀어볼 필요 있음. 

 

숫자로 이루어진 문자열 t와 p가 주어질 때, t에서 p와 길이가 같은 부분문자열 중에서, 이 부분문자열이 나타내는 수가 p가 나타내는 수보다 작거나 같은 것이 나오는 횟수를 return하는 함수 solution을 완성하세요.

예를 들어, t="3141592"이고 p="271" 인 경우, t의 길이가 3인 부분 문자열은 314, 141, 415, 159, 592입니다. 이 문자열이 나타내는 수 중 271보다 작거나 같은 수는 141, 159 2개 입니다.

function solution(s) {
    let answer;
    sArray = [...s.split(" ")];
    console.log(sArray);
    let answerArray = sArray.map((items) => {
        let arrofItems = [...items];
        for (let i = 0; i < items.length; i++) {
            if (i % 2 === 0) {
                arrofItems[i] = arrofItems[i].toUpperCase();
            } else {
                arrofItems[i] = arrofItems[i].toLowerCase();
            }
        }
        let newItems = arrofItems.join("");
        return newItems;
    });
    return (answer = answerArray.join(" "));
}

 

내가 간과했던 점들. 

1. 문자열은 '불변'한다. 문자열의 일부를 변하게 만드려면 배열 형태로 다시 만들어 준 다음에, 바꿔야만 한다.

2. 문제를 제대로 안 읽었다. 홀수 번째 줄은 '소문자로' 만들 필요가 있었다. -> 문제를 메모장에 적으면서 하자. 

 

자연수 n이 매개변수로 주어집니다. n을 3진법 상에서 앞뒤로 뒤집은 후, 이를 다시 10진법으로 표현한 수를 return 하도록 solution 함수를 완성해주세요.

function solution(n) {
    let answer = 0;
    let answerArray = [];
    let i = n;
    while (i) {
        answerArray.push(i % 3);
        i = Math.floor(i / 3);
    }
    for (let index = 0; index < answerArray.length; index++) {
            answer += answerArray[index] * 3 ** (answerArray.length - index - 1)
    }
    return answer;
}

내가 간과했던 점들

잠깐!!!!! 그 전에!!!!! 진수 변환은 어떻게 한다?

 

n을 m진법으로 변환하려면?

n이 0이 될 때까지 m으로 나누면서 나온 나머지를 붙여버리면 된다. 

 

45를 3진법으로 한다고 가정해보자. 

첫 번째 나머지는 0이다.

두 번째 나머지 역시 0이다. 

세 번째 나머지는 2.

네 번째 나머지는 1이다. 

 

그래서 네 번째 나머지부터 차례차례 1 + 2 + 0 + 0이 되어 1200이 된다. 

 

근데 실제 출력 결과는? 0 0 2 1이 될 거다. 

 

즉 우리는 굳이 '리버스'를 쓰지 않아도 push만 넣어도 문제에서 요구하는 '앞뒤로 뒤집는다'로 해결할 수 있다. 

 

그렇다면 역으로 n진법의 숫자를 10진법으로 변환하기 위해서는? 

 

각 자릿 수에 3의 i제곱을 곱해서 더해주면 된다. 

 

21을 바꾼다고 가정해보자

 

이를 10진법으로 바꾸려면? 

 

1에 3의 0제곱을 곱한 값을 구한다.

3에 3의 1제곱을 곱한 값을 구한다.

 

그리고 이 두 개의 값을 더한다. 

 

그래서 21을 10진법으로 변환하면 7이다. 

    for (let index = 0; index < answerArray.length; index++) {
            answer += answerArray[index] * 3 ** (answerArray.length - index - 1)
    }

 

이 부분이 이걸 식으로 변환한 거다. 

 

제곱은 ** 을 쓴다.