저장을 습관화

프로그래머스 LV.0 분수의 덧셈 본문

코딩 테스트/프로그래머스 - 자바스크립트

프로그래머스 LV.0 분수의 덧셈

ctrs 2023. 5. 28. 23:58

프로그래머스 LV.0 분수의 덧셈

https://school.programmers.co.kr/learn/courses/30/lessons/120808

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

1. 문제 명

분수의 덧셈


2. 문제 설명

첫 번째 분수의 분자와 분모를 뜻하는 numer1, denom1, 두 번째 분수의 분자와 분모를 뜻하는 numer2, denom2가 매개변수로 주어집니다. 두 분수를 더한 값을 기약 분수로 나타냈을 때 분자와 분모를 순서대로 담은 배열을 return 하도록 solution 함수를 완성해보세요.

 

기약함수: 분모와 분자를 최대공약수로 나눈 분수

ex) 27/36 = (27/9)/(36/9) = 3/4


3. 제한 사항

0 <numer1, denom1, numer2, denom2 < 1,000


4. 예시

numer1 denom1 numer2 denom2 result
1 2 3 4 [5, 4]
9 2 1 3 [29, 6]


5. 기본 제공 코드

function solution(numer1, denom1, numer2, denom2) {
    var answer = [];
    return answer;
}


6. 제출한 내 답

6-1. 제출

function solution(numer1, denom1, numer2, denom2) {
    var answer = []; 
    let resnum = ((numer1 * denom2) + (numer2 * denom1)) 
    let resden = denom1 * denom2; 
    let gcd = 1; 

    for (let i = 2; i <= resden; i++) {
        if (resnum % i === 0 && resden % i === 0) {
            gcd = i;
        }
    };

    resnum = resnum / gcd;
    resden = resden / gcd;

    return answer = [resnum, resden];
}

 

6-2. VSC에 작성한 내용

function solution(numer1, denom1, numer2, denom2) {
    var answer = []; // 배열 answer 선언
    let resnum = ((numer1 * denom2) + (numer2 * denom1)) // 분자 만들기, 
    // 분수1의 분자와 분수2의 분모를 곱하고, 분수2의 분자와 분수1의 분모를 곱한다.
    let resden = denom1 * denom2; // 분수1과 분수2를 곱해 공통의 분모를 만든다.
    let gcd = 1; // 최대공약수 선언, 초기값 1

    for (let i = 2; i <= resden; i++) {
        if (resnum % i === 0 && resden % i === 0) {
            gcd = i;
        }
    };

    // 이제 resnum과 resden을 최대공약수로 나누고 싶어

    resnum = resnum / gcd;
    resden = resden / gcd;

    return answer = [resnum, resden];
}

// 요구조건 numer1/denom1 + numer2/denom2 = resnum/resden
// num은 분자, denom은 분모
// 여기서 / 는 나눗셈이 아닌 분수의 표시
// 시도한 방법
// 1) 예시처럼 1/2, 3/4라면 서로 상대방의 분모를 곱하여 4/8, 6/8으로 만든다.

// 2) 그 둘을 더한다. 10/8이 될 것이다.

// 3) 분자와 분모의 최대공약수를 구하여 나눈다. 여기서는 2이다. 5/4가 되었다.

// 4) 이것을 배열 [5, 4]로 표시힌다.

// 테스트
console.log(solution(1, 2, 3, 4));
console.log(solution(9, 2, 1, 3));

 

7. 특이사항

7-1. 시도한 방법 

1) 예시처럼 1/2, 3/4라면 서로 상대방의 분모를 곱하여 4/8, 6/8으로 만든다.

2) 그 둘을 더한다. 10/8이 될 것이다.

3) 분자와 분모의 최대공약수를 구하여 나눈다. 여기서는 2이다. 5/4가 되었다.

4) 이것을 배열 [5, 4]로 표시힌다.

 

 

7-2. 헷갈렸던 부분

최대공약수 구하는 방법을 몰라서 검색해서 나온 방법을 참고했다.

 

JavaScript에서  최대공약수(greatest common divisor)와 최소공배수(least common multiple) 구하는 방법

 

- 최대공약수

let getGCD = (num1, num2) => {
    let gcd = 1; // 변수 gcd의 선언. 초기값은 1
    
    for(let i=2; i<=Math.min(num1, num2); i++ ) {     											
    // 반복문, 변수 i의 초기값은 2이다. i는 num1과 num2중 작은값과 같아질때까지 반복할 것이며,
    // 매 사이클마다 i에 1씩 더한다
        if(num1 % i === 0 && num2 % i ===0){
        // num1에서 i를 나누었을때의 나머지와 num2에서 i를 나누었을때 나머지가 0이라면
            gcd = i; // 변수 gcd의 값이 변수 i의 값으로 재지정된다.
            // 최대공약수이므로 반복문이 끝날때까지 진행한다. 변수 gcd는 계속해서 바뀔 수 있다.
        }
    }

    return gcd;
}

console.log(getGCD(10, 8)); // 2
console.log(getGCD(29, 6)); // 1
console.log(getGCD(36, 16)); // 4

- 최소공배수

let getLCM = (num1, num2) => {
    let lcm = 1; // 변수 lvm 선언, 초기값은 1

    while(true){ // 반복문, 참이 될때까지 무한으로 반복한다. break가 필수이다.
        if((lcm % num1 === 0) && (lcm % num2 === 0)) {
            // 조건문, lcm에서 num1을 나눴을때의 나머지와, lcm에서 num2를 나눴을때의 나머지가 모두 0이라면 
            break; // 반복문을 종료한다.
        }
        lcm++; // 매 사이클마다 lcm에 1을 더한다.
    }

    return lcm;
}

console.log(getLCM(10, 8)); //40
console.log(getLCM(3, 6)); //6
console.log(getLCM(7, 6)); //42

[참고]

https://velog.io/@devjade/JavaScript%EB%A1%9C-%EC%B5%9C%EB%8C%80%EA%B3%B5%EC%95%BD%EC%88%98GCD-%EC%B5%9C%EC%86%8C%EA%B3%B5%EB%B0%B0%EC%88%98LCM-%EA%B5%AC%ED%95%98%EA%B8%B0

 

JavaScript로 최대공약수(GCD), 최소공배수(LCM) 구하기

최대공약수는 두 수 A와 B의 공통된 약수 중에 가장 큰 정수이다.최대공약수를 구하는 가장 쉬운 방법은 2부터 min(A, B)까지 모든 정수로 나누어보는 방법이다.두 수, 혹은 그 이상의 여러 수의 공

velog.io

 

위 방법은 참고한 블로그에 사용된 예시일뿐

아래와 같이 훨씬 영리한 방법도 많이 있다.

 // 두수 a, b 를 넣는다.
  function greatest(a, b) {
  
    // b(나머지)가 0이면 a(직전 나머지)를 반환하고 탈출 (base case)
    if (b === 0) return a;
    
    // b를 앞으로 보내고 a % b 를 나눈 나머지(r)을 매개변수로해서 재귀함수로써 호출
    return greatest(b, a % b);
  }

[참고] https://devbirdfeet.tistory.com/257

 

화살표 함수와 삼항연산자에  빨리 익숙해져야겠다.

기본 함수 형식에 적응한 후 넘어가면 된다라고 들어서 느긋하게 있었는데

요즘 검색해서 나오는 게시글들은 기본 형식으로 길게 풀어쓰는게 잘 없네

 

7-3. 반성

쉬운 부분은 어떻게 직접 작성했다 하더라도 정작 제일 중요한 최대공약수 구하는 방법은 남의 코드를 가져다 썼다.

실력을 더 기르자.. 어떻게 하면 좋을지 다시 한번 더 생각해보자..

 

그 외에도 코드 제출 후 chatgpt에게 코드 검토를 맡겼는데

최대 공약수 구하는 부분에서 아래와 같이 수정해 주었다.

for (let i = Math.min(resnum, resden); i >= 2; i--) {
  if (resnum % i === 0 && resden % i === 0) {
    gcd = i;
    break;
  }
}

resnum /= gcd;
resden /= gcd;

1) 변수 i는 resnum과 resden 중 더 작은 수로 삼을 것

나는 이번 테스트에서 무조건 resnum이 resden보다 클것이라 생각하여 기준을 resden로 잡았지만

다시 생각해보니 1/4 + 1/3 = 7/12 처럼 resnum이 작은 경우도 충분히 가능하다.

 

2) 변수 i를 1씩 줄이고, 최대공약수를 구했다면 break문을 사용하여 불필요한 반복을 줄일것

최대공약수는 그 수가 클 경우가 크므로 큰 수에서부터 하나씩 내려오는게 반복을 더 줄일 수도 있을 것이다.

최대공약수를 찾았다면, 그보다 아래로는 더 내려갈 필요가 없으니 break문으로 빠져나오자

 

3) resnum = resnum / gcd; 도 간단하게 줄일 수 있음

 

다음에 다시 참고하자..


8. 다른 사람이 작성한 답

8-1. 재귀함수

function fnGCD(a, b){
    return (a%b)? fnGCD(b, a%b) : b;
}
// a에서 b를 나눈 나머지가 1이상이라면 그 나머지 값을 이용하여 다시 한번 fnGCD 함수를 타게되고,
// a에서 b를 나눈 나머지가 0이라면 b가 최대공약수가 되어 return한다.

function solution(denum1, num1, denum2, num2) {
    let denum = denum1*num2 + denum2*num1;
    let num = num1 * num2;
    let gcd = fnGCD(denum, num); //최대공약수

    return [denum/gcd, num/gcd]; // 별도의 분자와 분모의 값 재지정 없이
    // 그대로 배열에서 계산식을 적용하였다.
}

참 기발한 방법이라고 생각한다. 

내 코드에서 몇줄이나 아낄수 있었다.

 

8-2. ????

var g=(a,b)=>b?g(b,a%b):Math.abs(a),l=(a,b)=>(a*b)/g(a,b),p,q,solution=(a,b,c,d)=>{return p=l(b,d),q=a*p/b+c*p/d,[q/g(p,q),p/g(p,q)]}

이건 보고도 모르겠다

따라도 못하겠다

얘 뭐지