[Lv.2] 숫자의 표현

2023-10-02

문제 설명

Finn은 요즘 수학공부에 빠져 있습니다. 수학 공부를 하던 Finn은 자연수 n을 연속한 자연수들로 표현 하는 방법이 여러개라는 사실을 알게 되었습니다. 예를들어 15는 다음과 같이 4가지로 표현 할 수 있습니다.

  • 1 + 2 + 3 + 4 + 5 = 15
  • 4 + 5 + 6 = 15
  • 7 + 8 = 15
  • 15 = 15

자연수 n이 매개변수로 주어질 때, 연속된 자연수들로 n을 표현하는 방법의 수를 return하는 solution를 완성해주세요.

제한 사항

  • n은 10,000 이하의 자연수 입니다.

풀이

나의 풀이 방식대로 문제를 한 번 읽고 가장 먼저 제한 사항을 본다.

제한 사항을 바탕으로 한 번 반복을 했을 때 최악의 경우 10,000이다.

이중 반복을 하게 되면 100,000,000이다.

여기서 한 번 고민을 하게 된다.

웬만하면 이중 반복은 좋지 않긴 하지만 이중 반복을 하는 방법 말고는 다른 방법이 바로 떠오르지 않았다.

따라서 완전탐색을 이용하기로 했다.

  1. n만큼 반복을한다.
  2. 1-n까지 더해가며 n이 되면 break를 건다.

완전탐색이기 때문에 간단하다...그냥 무식하게 냅다 반복을 갈겨버리면 된다...

이게 맞나 싶기도 하지만 도전해본다!!!!

역시나 방법은 맞았지만 효율성 테스트 1개에서 시간 초과가 뜬다.

딱 1개만 시간초과가 뜨는 걸 보니 이 방법이 아예 틀린 건 아닌 거 같아 인터넷을 찾아봤다.

내 코드를 python으로 짰을 때에는 통과한다??!?!!

이게 무슨.....한 번 어이가 없어지며 다시 고민을 해본다.....

혹시나 해서 let 선언을 var 선언으로 바꿔줬다...........

된....다.......이게 왜!?!?

여기에 대해서는 맨 마지막 추가 설명에서 설명하겠다.

통과 코드

function solution(n) {
  var answer = 0;
  
  for (let i = 1; i < n + 1; i++) { // n만큼 반복
    var sum = 0; // 15가 되면 answer 카운팅하고 break 걸고 빠져나오기 위한 변수
    for (let j = i; j < n + 1; j++) { // j = i인 이유는 1부터 연속해서 n이 되는 숫자들의 조합은 1개의 경우의 수밖에 없기 때문에 다시 볼 필요가 없기 때문
      sum += j;
      if (sum === n) { // n과 딱 같아질 때에만 카운팅해줌
        answer++;
        break;
      }
      if (sum > n) { // 커져버리면 탈락이고 더 볼 필요도 없기 때문에 break
        break;
      }
    }
  }
  
  return answer;
}

추가 설명

var과 let의 시간차이?

var과 let의 차이는 호이스팅 차이만 있는 줄 알았는데 그것이 아니었다....

이것을 설명하기 전에 간단히 var과 let의 차이에 대해 설명해 보려고 한다.

먼저 var 선언 방식은 호이스팅 과정에서 변수가 선언이 됨과 동시에 undefined로 초기화 과정까지 일어난다. 따라서 선언 전에 호출하려고 하면 에러가 뜨지 않고 undefined가 뜨게 된다.

반면 let 선언 방식은 호이스팅이 발생하지만 초기화 과정이 없다. 이 부분에 대해 많은 사람들이 let과 const는 호이스팅이 발생하지 않는다고 생각한다. 틀린 생각이다. 호이스팅이 발생은 하지만 let, const는 선언문과 만날 때까지 할당이 이뤄지지 않고 TDZ(Temporal Dead Zone)에 있는 것이다.

더 깊게 들어가면 글의 요지와 맞지 않기 때문에 왜 TDZ에 빠지게 되는지는 여러분이 직접 찾아보길 권장한다.

아무튼 설명이 길었지만 그래서 var과 let의 차이 중에 시간적인 차이는 왜 발생하나???

이건 나도 원래 몰랐던 것이라 찾아봤다......

A Lexical Environment is a specification type used to define the association of Identifiers to specific variables and functions based upon the lexical nesting structure of ECMAScript code. (중략) Usually a Lexical Environment is associated with some specific syntactic structure of ECMAScript code such as a FunctionDeclaration, a BlockStatement, or a Catch clause of a TryStatement and a new Lexical Environment is created each time such code is evaluated.

(발번역) 렉시컬 환경은 ECMAScript 코드의 렉시컬 중첩 구조를 기반으로 특정 변수 및 함수에 대한 식별자 연결을 정의하는 데 사용되는 규격 유형입니다. (중략) 일반적으로 렉시컬 환경은 FunctionDeclaration, BlockStatement 또는 TryStatement의 Catch 절과 같은 ECMAScript 코드의 특정 구문 구조와 연관되며 해당 코드가 평가될 때마다 새로운 렉시컬 환경이 생성됩니다.

위 글은 ECMAScript2015 Specfication - Lexical Environments 여기서 갖고 온 글로 이 얘기에 따르면 변수와 함수는 scope 기준으로 Lexical Environment에 할당이 된다. let과 const는 블록 스코프를 따르기 때문에 if 또는 for 문과 같이 블록 영역에서 선언될 경우 새롭게 생성되는 Lexical Environment에서 시스템적인 비용이 발생한다.

반면에 함수 스코프를 갖는 var은 위와 같은 측면에서 자유롭기 때문에 블록 스코프를 따르는 let, const보다 빠르다는 결론이 나온다.

그런데 ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ

이게 과연 진짜일까? 이게 진짜이면 let보다 var를 실제 프로젝트에서 많이 사용할 것이다..하지만 그렇지 않다.

갑자기?라는 생각이 들 수 있다. 혹시나 해서 실제로 성능테스트한 글 들을 보고 왔다....

충격적이게도 실제 성능테스트한 글들에서는 var이 let보다 느릴 때도 있고 똑같을 때도 있고 빠를 때도 있고 그렇다.

이제는 차이가 없다. 이제는 차이가 없다?? 그렇다. 예전에는 차이가 실제로 있었다.

let, const ES6(2015)에 출시되었다. 알아보니 2016년까지는 브라우저 엔진들이 이 let, const의 최적화를 해내지 못했다고 한다.

하지만 이제는 최적화가 잘 진행된 상태이고 실제로 차이도 없었다.

그렇다면 프로그래머스는??

프로그래머스의 JavaScript의 런타임 환경은 Node.js 16.17.0 버전을 사용하고 있다???

그러면 Node.js는 V8 엔진을 사용하기 때문에 해결이 됐을텐데....

이러면 문제가 없어야 하는데...나도 아직 풀리지 않은 의문이다..ㅎㅎㅎ

근데 내 예상으로는 현재도 특정 부분에서만 let, var 차이가 없는 것 같고 조금씩은 있는 것 같다.

따라서 프로그래머스에서 문제를 풀땐 var을 쓰도록하자...ㅎㅎ

혹시 아는 사람 있다면 알려주세요..ㅇㅅㅇ

brute force search

프로필 사진
TaeWoo Kim
Junior Frontend Engineer