티스토리 뷰

728x90

요즘 들어 알고리즘 문제를 자바스크립트로 한두 문제씩 풀고 있습니다.

BOJ를 자바스크립트로 시도해보셨다면 아시겠지만, 들어오는 입력을 모두 한 배열에 때려 박고 각각 인덱스로 접근해 사용하게 됩니다. 저는 이게 너무 적응이 안 돼 방법을 찾던 중 괜찮은 아이디어가 떠올라 공유하게 되었습니다.

 

중간 설명 없이 바로 이용하고 싶으신 분은 여기를 클릭해주세요.

input 함수 만들기

백준 사이트의 컴파일 실행 도움말에서는 Node.js 입력을 다음처럼 소개합니다.

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);

만약 공백으로 구분된 값들이 여러 줄로 들어온다면 다음과 같은 형식으로 사용하겠죠?

var fs = require('fs');
var input = fs.readFileSync('/dev/stdin').toString().split('\n');

var line0 = input[0].split(' ');
var line1 = input[1].split(' ');
var line2 = input[2].split(' ');
...

하지만 이 방식은 너무 불편합니다. 입력값이 필요할 때마다 배열로 접근해야 하는데, 입력이 많아질수록 인덱스가 헷갈려 신경 쓸게 하나 더 늘어나게 됩니다.

 

 

간단한 아이디어를 통해 input 인덱스의 고려 없이 그저 들어오는 순서대로 입력받는 함수를 구현할 수 있습니다.

자바스크립트의 클로저(closure)를 이용해 특정 함수 내에서만 접근할 수 있는 변수를 만들고, 그 값을 input의 인덱스로 이용하면 됩니다.

이에 대한 자세한 설명은 javascript.info/closure을 참고해주세요. 링크의 코드를 살짝 응용하면 다음 코드를 얻을 수 있습니다. 

const fs = require('fs');
const stdin = fs.readFileSync('/dev/stdin').toString().split('\n');

function makeInput(){
    let line = 0;

    return function(){
        return stdin[line++];
    };
};

const input = makeInput();

이렇게 반환된 input 함수는 실행될 때마다 stdin을 한 줄씩 반환합니다.

비록 작동 원리는 다르지만, BOJ에 한해 파이썬의 input() 함수와 똑같은 방법으로 사용할 수 있습니다.

 

코드를 좀 더 줄일 수도 있습니다.

즉시 실행 함수(Immediately-Invoked Function Expression)와 ES6에서 도입된 화살표 함수를 이용합시다.

const fs = require('fs');
const stdin = fs.readFileSync('/dev/stdin').toString().split('\n');

const input = (() => {
    let line = 0;
    return () => stdin[line++];
})();

 

결과적으로 코드 딱 4줄을 추가해서 편하게 코딩할 수 있게 되었습니다.

input()과 함께 구조 분해 할당(Destructuring assignment), split(), map(), forEach(), reduce() 등을 적절히 이용하면 더 간단한 코딩이 가능합니다.

 

Windows 로컬에서 예제 테스트하기

지금은 맥북을 쓰지만, 이전에는 Windows10 환경에서 VSCode를 이용해 백준 문제를 풀었습니다. 맥 OS, 리눅스는 유닉스 기반이라 /dev/stdin를 읽어주면 터미널상에서 예제를 입력할 수 있으나 윈도우에서는 이게 불가능합니다. 그래서 처음엔 입력 예제를 다른 파일에 붙여 넣고, 그 파일을 읽어 실행하게끔 했습니다. 이건 너무 귀찮은 작업입니다. 입력이 바뀔 때마다 예제 파일로 이동 - 붙여넣기 - 저장 - 원래 코드로 돌아오기 4단계를 거치니까요...

 

파일을 따로 만들지 않는 방법을 고민하다 템플릿 문자열을 이용하기로 했습니다.

const fs = require('fs');
// const stdin = fs.readFileSync('/dev/stdin').toString().split('\n');
const stdin = `10 10 3
13 2 5 11 7 8 2 4 9 10
1
2
3
8
9
10
11
16
17
49
`.split('\n');

템플릿 문자열을 이용하면 개행을 유지하며 BOJ의 예제 그대로 복사-붙여넣기를 할 수 있습니다.

 

쓰다 보니 BOJ에 코드를 올릴 때 로컬 stdin을 지우고, 원래 stdin의 주석을 푸는 것마저 귀찮습니다...

그래서 최종적으로 다음처럼 사용하게 되었습니다.

const fs = require('fs');
const stdin = (process.platform === 'linux'
  ? fs.readFileSync('/dev/stdin').toString()
  : `10 10 3
13 2 5 11 7 8 2 4 9 10
1
2
3
8
9
10
11
16
17
49
`
).split('\n');

실행중인 프로세스가 리눅스라면(BOJ 채점 환경) stdin을 통해 입력을 읽어 들이고, 그렇지 않으면 제가 직접 입력한 예제가 적용됩니다. 이 방식으로 코드 제출 시 따로 수정 없이 그대로 붙여 넣을 수 있게 됐습니다.

 

문제를 풀어보자

설명했던 방법을 이용해 작성한 코드를 예시로 올립니다. 

10950 A+B - 3

 

10950번: A+B - 3

두 정수 A와 B를 입력받은 다음, A+B를 출력하는 프로그램을 작성하시오.

www.acmicpc.net

제출된 코드

 

공유 소스 보기

 

www.acmicpc.net

const fs = require('fs');
const stdin = (process.platform === 'linux'
    ? fs.readFileSync('/dev/stdin').toString()
    : `5
1 1
2 3
3 4
9 8
5 2
`
).split('\n');

const input = (() => {
    let line = 0;
    return () => stdin[line++];
})();

let t = input();
while (t--) {
    const [a, b] = input().split(' ').map(Number);
    console.log(a + b);
}

 

 

 

달팽이 리스트 - 2019년 홍익대학교 프로그래밍 경진대회

 

17827번: 달팽이 리스트

첫째 줄에 노드의 개수 N(2 ≤ N ≤ 200,000), 질문의 횟수 M(1 ≤ M ≤ 200,000), N번 노드가 가리키는 노드의 번호 V(2 ≤ V ≤ N)가 공백으로 구분되어 주어진다. 둘째 줄에 N개의 정수 C1, C2, …, CN이 공백

www.acmicpc.net

제출된 코드

 

공유 소스 보기

 

www.acmicpc.net

const fs = require('fs');
const stdin = (process.platform === 'linux'
    ? fs.readFileSync('/dev/stdin').toString()
    : `10 10 3
13 2 5 11 7 8 2 4 9 10
1
2
3
8
9
10
11
16
17
49
`
).split('\n');

const input = (() => {
    let line = 0;
    return () => stdin[line++];
})();

let [n, m, v] = input().split(' ').map(Number);
const cycle = [], non = [];
v--;
input()
    .split(' ')
    .forEach((x, i) => {
        x = +x;
        if (i < v) non.push(x);
        else cycle.push(x);
    });

const ans = [];
for (let i = 0; i < m; i++) {
    const k = +input();
    if (k < v) ans.push(non[k]);
    else ans.push(cycle[(k - v) % (n - v)]);
}
console.log(ans.join('\n')); 

 

728x90

'알고리즘 > 꿀팁' 카테고리의 다른 글

프로그래머스 vim에서 space n칸 ↔ tab 변환 하기  (0) 2021.02.07
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함