본문 바로가기
공부/알고리즘

백준에서 JS로 문제 풀이하기 + 이런저런 메모(+추가: 2023.11.22)

by Piva 2023. 10. 23.
  • 앞서 올린 백트래킹 게시물에서 언급했듯, 얼마 전부터 시간이 날 때 조금씩조금씩 알고리즘 문제 풀이를 하고 있다.
  • 주로 백준에서 문제를 풀고 있는데, 백준에서 문제를 풀 때 어떻게 풀고 있는지 + 문제 풀 때 개인적으로 알아두면 좋을 것 같은 점을 간단하게 기록해두려 한다.

백준에서 JS로 문제를 풀기 위한 세팅

  예전에 백준에서 문제를 풀 때는 C++를 사용했는데, 이제는 거의 잊어버리기도 했고 업무를 JS로 하다 보니 JS로 문제를 풀어야겠다는 생각으로 아무 생각 없이 언어 설정을 살펴보았다. 하지만 자바스크립트는 목록에 보이지 않았고... node.js만 덩그러니 있어서 뭔가 싶던 도중 검색을 통해 JS는 node.js를 선택해야 함 + 입력값을 직접 처리해야 함 이라는 정보를 얻게 되었다.

 

  JS로의 문제풀이는 주로 프로그래머스에서 했었고, 프로그래머스에선 입력값을 따로 처리할 필요가 없었던지라 당황했지만, 검색을 통해 레퍼런스를 얻어 쉽게 입력값을 처리할 수 있었다. 먼저, 입력값을 받는 데에는 크게 2가지의 방법이 있다.

 

fs 모듈 사용

  하나는 node.js의 File system 모듈을 사용하는 것이다. 아래는 백준 도움말 사이트에서 예제로 올린 것을 가져온 것이다.

var fs = require('fs');
var input = fs.readFileSync('/dev/stdin').toString().split(' ');
var a = parseInt(input[0]);
var b = parseInt(input[1]);
console.log(a+b);

  다만 이 방법은 많은 곳에서 추천하지 않고 있는데, /dev/stdin을 사용하면 런타임 에러가 나는 경우가 있기 때문이다. 그래서 사용하는 방법이 아래의 방법이다.

 

readline 모듈 사용

  또다른 방법은 readline 모듈을 사용하는 것이다.

const readline = require("readline");
const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
});

rl.on("line", (line) => {
  // 입력을 줄로 받음
}).on("close", function () {

  process.exit();
});

  위 코드는 입력을 한 줄씩 받아 처리한다. 문제의 입력값 형식에 맞게, 자신이 사용하려는 목적에 맞게 데이터를 처리하는 코드를 추가로 넣어주면 된다.

 


백준에서 JS로 문제를 풀며 알게 된 것

  얼마간 문제를 계속 풀어보며 알게 된 점이 있다. 문제 풀 때 놓치거나 알아두면 좋은 점인데 앞으로도 새롭게 알게 된 점은 여기에 추가해두려 한다.

 

1. console.log 보다 문자열을 사용하면 수행시간을 줄일 수 있다.

  입력 한 줄에 대해 결과값을 출력해야 하는 문제와 같이, 출력값이 많은 문제는 그때그때 console.log를 찍으면 시간이 상당히 오래 걸린다. 이를 해결하기 위한 방법에는 문자열을 사용하는 방법이 있는데, 매 결과를 console.log로 찍는게 아니라 하나의 문자열 변수에 출력값을 붙이는 방법이다.

for (let i = 0; i < arr.length; i++) {
// 아래와 같이 매 결과를 그때그때 console.log()로 찍는 것은 시간이 오래 걸린다.
	console.log(i);
}

// ====================================
let answer = "";

for (let i = 0; i < arr.length; i++) {
// 매번 결과를 찍는 대신 문자열 변수에 붙여 나중에 한꺼번에 출력한다.
    answer += `${i}\n`;
}

console.log(answer);

 

  내 경우는 아무 생각없이 출력 한줄 한줄에 console.log를 사용했다가 시간 초과가 났던 문제가 있었는데, 이 때는 출력이 문제라는 걸 몰랐어서 코드에 문제가 있나 싶었다가 게시판 글을 참고해서 출력시간 또한 줄일 수 있음을 새로이 알게 되었다. 그 뒤로는 가급적 문자열을 사용해서 한꺼번에 결과를 출력하는 방향으로 문제를 풀고 있다.

 

 

2. -0과 0을 조심하기

  가끔 음수로 숫자 연산을 하면 -0이라는 결과값이 나올 때가 있다. 아주 가볍게 알아보니 자바스크립트는 숫자 표현에 IEEE 754라는 표준을 사용하고 있고, 이 표준에선 -0과 +0을 구분하기 때문이라고. (참고: 스택오버플로우) 일단 단순히 비교식으로 -0과 0, +0을 비교해보면 true가 나온다. 위 스택오버플로우 글을 참고하면 Object.is 로는 -0과 0(+0)이 같지 않은 것으로 나온다고.

 

  이를 알게 된 계기는 백트래킹 문제 중 하나인 "14888. 연산자 끼워넣기"문제인데, 어렵지 않게 구현을 끝내고 예제 또한 다 맞음을 확인한 후 제출하니 채점을 시작하자마자 오답이 뜬 것이다. 게시판의 다른 예제들을 다 넣어봐도 맞아서 고민하던 와중, 구세주처럼 -0에 대한 게시글을 보아 문제를 파악할 수 있었다.

 

  만약 문제를 푸는 데 문제에 음수 연산이 포함되어 있다면, 해당 연산값이 -0이 되는 상황을 고려하고 이를 미리 처리해주는 것이 좋을 것 같다.

 

 

3. 숫자 범위 확인하기

  문제 풀이 시 코드 내 숫자 범위가 커져, 자바스크립트의 기본 숫자 객체인 Number의 범위를 벗어날 때가 있다. 일례로 백준의 "1890. 점프" 문제가 있다.

 

  이 문제의 출력을 보면, 정답이 2^63-1보다 작거나 같다라고 서술되어 있다. 그런데 자바스크립트의 Number의 최대치는 2^53-1이므로, 이보다 더 큰 값을 나타낼 수 있는 BigInt를 사용해야 정답을 도출할 수 있다.

 

  따라서 문제 풀이 시 미리 문제 내 수들의 범위를 확인하고, 값이 너무 클 가능성이 존재할 경우 BigInt형을 쓰는 것이 좋을 것 같다. 여담으로 BigInt형을 사용할 시, 답을 출력할 때 toString()을 사용하여 일반적인 숫자 형태로 출력하는 것을 잊지 말자.

const num = BigInt(1);

console.log(num); // 출력: 1n
console.log(num.toString()); // 출력: 1

'공부 > 알고리즘' 카테고리의 다른 글

그래프 + 그래프 순회 정리  (0) 2023.11.17
유클리드 호제법  (1) 2023.10.29
백트래킹  (1) 2023.10.15
[~0718] 알고리즘  (0) 2021.07.19
[0629] 알고리즘  (0) 2021.06.30