240830 TIL - Node 입문 2주차 1, 유클리드 그게 누군데

LIHA·2024년 8월 30일
0

내일배움캠프

목록 보기
32/108
post-thumbnail
post-custom-banner

알고리즘

유클리드가 대체 누군데요 - 유클리드 호제법

최소공배수는 어찌저찌 맞게 구한 것 같은데 최대공약수가 이상하다. 아무리 해도 나오지가 않는다.
for문 안에 if를 계속 거는 것은 좋지 않다고 했었는데, 한번에 나올 방법이 없을까?
-> 고민해봤지만 혼자서는 떠올릴 수 없었다. 이 해법은 '유클리드 호제법' 이라는 방법이 있었다.
유클리드를 모르는건 아니지만 유클리드 기하학에서밖에 이름을 들어보지 못했는데(...)
구원의 위키독스

호제는 서로 나눈다는 뜻. [3, 12] 같은 숫자쌍이 아니고서야 분명히 서로끼리는 나누어 떨어지지 않을 것이다.
하여 큰 수를 작은 수로 나눴을 때의 몫을 다시 큰 수 자리에 넣고 나머지를 다시 작은 수 자리에 넣어, 나머지가 0이 될 때 까지 나누기를 반복하는 것이다. 그 나누기를 반복하다가 나머지가 0이 되는 순간의 몫이 최대공약수가 되는 것.

    while (n !== 0) {
      // 51, 21이라 가정하면 이렇게만 썼을 때 m = 21이 되어버린다 
      // 같은 수로 나누는 꼴이니 n이 바로 0이 나온다. 그러니 그냥 인풋이 리턴되어 버림.
        m = n;
        n = m % n;
    } 

다만 while문을 이렇게만 써줄 경우 제대로 동작하지 않으니 주의.
(언어의 특성이 달라서 JS는 기대한 대로 한줄 씩 실행되지 않는다고 한다. Python은 잘 굴러간다고.)

while문은 이렇게 써주자. 자리바꾸기가 필요하다.

    while (n !== 0) {
      // 51, 21이라 가정하면  tmp = 21, n = 51 % 21이므로 9, m에 tmp인 21을 넣게 된다.
      // 이렇게 자리바꾸기 식으로 회당 연산의 작은수와 나머지를 보존하여 큰수와 작은수 자리에 집어넣어주게 된다.
      // 그리고 우리는 '나머지가 0인' 수를 구해야 하니까 나머지인 n값이 0이 아닐 동안만 돌아가는 것. 
        let tmp = n;
        n = m % n;
        m = tmp;
    } 

의외로 최소공배수는 맞았다. 그런데 불필요한 for문과 if문을 걸어줄 필요는 없었다.

    for (let i = n; i <= m; i++) {
        if (answer[0] !== 1) {
            answer[1] = (m * n) / answer[0];
        } else answer[1] = m * n;
    }

원래는 이렇게 썼었는데, 생각해보면 answer[0] === 1이면 어차피 나눠도 그대로 m * n이므로 윗 식만 써도 무방했다!

    answer[1] = (m * n) / answer[0];

호영 튜터님의 말씀

  • solution이라는 함수 하나로만 풀지 않아도 된다! 여러개 함수로 푸는 것이 사고의 확장에도 좋다.
  • 어차피 다른 언어에서는 하나로 풀지 않는 경우가 대부분이다.
  • Golang은 하나의 함수로는 알고리즘 풀기가 힘들다. 굳이 함수 한 개로 풀 필요가 있나? 싶어 여러개로 푸셨다고.

내 알고리즘이 실행되지 않는 것은 스불재였다 - tmp의 필요성

TMI : 스불재는 스스로 불러온 재앙 의 약자

뭐에요, 바꿔주세요. 왜 교환 불가야.
아무튼. 돌아가지 않는 문제의 코드.

function solution(left, right) {
    var answer = 0;
    
    for (let i = left; i <= right; i++) {
        if(Number.isInteger(i)) {
            i = -i;
        }
        answer += i;
    }
    return answer;
}

원했던 것: 약수의 개수가 홀수인 수에 -를 붙여서 answer에 더해줘야지
실행 결과: 뜬금 음수가 된 i는 두배가 된 증감문을 쌔가 빠지게 돌아가려다가 실행시간을 초과해버림

  • 기주 튜터님의 조언: 약수의 개수가 홀수일 때 따로 빼주고 싶다면 별도의 변수가 있는 것이 좋겠다.

그래서 수정한 방향: 제곱수인지 판별해보고 제곱수라면 마이너스를 붙여주자. 그런데 어떻게?
-> Math.sqrt(숫자)의 바깥에 정수인지 판별하는 메소드인 Number.isInteger()를 써서, 제곱근이 정수이면 약수의 갯수는 홀수인걸로 간주!

마침내 통과한 코드

function solution(left, right) {
    var answer = 0;
    
    let dividors = 0;
    for (let i = left; i <= right; i++) {
            dividors = i;
        if(Number.isInteger(Math.sqrt(i))) {
            dividors = -i;
        }
        answer += dividors;
        console.log(dividors)
    }
    return answer;
}

원래 내가 구현하고 싶었던, 프로그래머스에서 발견한 코드

function solution(left, right) {
  let answer = 0;

  for (let i = left; i <= right; i++) {
    let count = 0;
    for (let j = 1; j <= i; j++) {
      if (i % j === 0) count++;
    }
    if (count % 2) answer -= i;
    else answer += i;
  }

  return answer;
}

정섭 튜터님의 말씀

<추천 툴>
thunder client
SQLTool
VS Code는 마이크로소프트에서 만든 툴이라 거의 모든 기능이 다 확장 프로그램으로 들어가 있다. 그래서 좋은 익스텐션을 고르는 안목이 중요하다.

  • '유니언'이라는 게 있다. 이거일 수도 있고 저거일 수도 있다는 것.
    -> 그래서 'find는 항상 undefined의 유니언'이다. (찾았는데 안 나올 수도 있으니까)
    이 유니언된 undefined나 null을 지워주는게 굉장히 중요하다! 이게 JS에서의 exception handling이다.

Node

왜 나는 goodId 조회가 안 되지? -> 똑같이 친 게 아니었다!!

  • 올바른 코드
router.get('/goods/:goodsId/', (req, res) => {

  const goodsId = req.params.goodsId;
  const foundGood = goods.find((oneGoods) => oneGoods.goodsId === +goodsId);
  // undefined를 반환하지 않도록 하자
  
  if (!foundGood) throw new Error('업성');
  return res.status(200).json({
    goods: foundGood
  });
});
  • 오류를 찾아 헤매던 틀린 코드
router.get('/goods/:goodsId/'), (req, res) => {

  const goodsId = req.params.goodsId;
  const foundGood = goods.find((oneGoods) => oneGoods.goodsId === +goodsId);
  // undefined를 반환하지 않도록 하자
  
  if (!foundGood) throw new Error('업성');
  return res.status(200).json({
    goods: foundGood
  });
};

이 괄호 하나 때문에 정섭튜터님과 정말 이것 저것 모두 다 실행해 보았지만 되지 않았다... 이 오류는 웅상님이 잡아주셨다.

왜 나는 상품등록이 안 되지? -> URL 맨 앞에 / 안붙이면 제대로 작동 안 한다!

여기에 'goods/' 라고 썼더니 POST가 제대로 작동하지 않았다.
문득 정섭 튜터님이 말씀해주신 'URL 앞에 슬래시를 안 붙이면 제대로 동작하지 않는다' 가 생각나서 붙여봤더니 잘 됐다.

다시 돌아온 객체 구조 분해 할당 - key값과 value값의 이름이 같으면 key만 써줘도 ok

스키마 구현 시 반드시 객체를 중괄호로 쓰지 않아도 괜찮다!

category나 price처럼 왼쪽이 필드, 왼쪽이 데이터타입인 식으로 써줘도 된다.

mongoDB에서 데이터를 조회할 땐 .exec()를 붙여주자

이걸 붙이지 않으면 제대로 실행되지 않을 수 있으니 주의!

profile
갑자기 왜 춤춰?
post-custom-banner

0개의 댓글