Javascript를 활용해서 백준 사이트에서 문제를 풀 때 사용하기 좋은 입력 방법을 찾아서 정리한 글입니다.
백준을 자바스크립트로 풀기 어려운 이유
코딩 문제를 해결하는 대표적인 사이트에 백준, 프로그래머스가 있다.
프로그래머스는 아래 코드와 같이 입력받는 값이 함수의 매개변수로 주어지기 때문에 입력받는 부분을 따로 만들 필요가 없다.
function solution(age) {
var answer = 0;
return answer;
}
그러나 백준은 입출력을 stdin, stdout 방식으로 받기 때문에 입출력 과정을 전부 명시해줘야 한다.
자바스크립트는 브라우저 환경에서 사용되는 목적으로 개발된 언어이므로, Node.js가 등장하기 전에는 백준과 같은 환경에서 표준 입력(stdin)을 직접 다루는 것이 불가능했다.
Node.JS란?
Node.js는 자바스크립트를 웹 브라우저 밖에서도 실행할 수 있게 해주는 도구라고 생각하면 된다.
Javascript 코드를 웹 브라우저가 아닌 외부 환경에서 실행할 수 있도록 해주는 환경이다.
1. 입력의 어려움
node.js 덕분에 입력을 처리할 방법이 생겼지만 브라우저의 이벤트를 처리하는 언어로써 입출력이 C++, python에 비해 직관적이지 않고 복잡하다.
2. 시간 초과, 메모리 초과
인터프리터 언어인 javascript는 컴파일 언어인 c, c++ 보다 시간이 오래 걸리기 때문에 시간제한을 빡빡하게 걸어놓은 문제는 해결하지 못하는 경우가 있다.
추가로 c/c++처럼 메모리에 직접 접근하는 것이 불가능하기 때문에 메모리 제한에도 쉽게 막히는 언어이다.
👀 백준에서 javascript로 문제 풀 때 node.js로 풀리는 문제인지 확인하고 풀자!
node.js 환경으로 javascript 입력받기
방법 1. fs 모듈
방법 2 readline 모듈
시간 효율성으로 fs 모듈이 더 빠르기 때문에 fs모듈로 ps를 하는 것이 더 효율적이긴 하다.
fs 모듈을 사용해 입력데이터 받기
Node.js의 파일 시스템 모듈을 사용하여 파일의 내용을 한 번에 입력받고 이를 쪼개어 원하는 변수에 넣는 방식
일단 ide에서 풀기 위해 input.txt에 전체 입력을 넣고 이를 불러와서 쪼개는 방식으로 처리한다.
1. 파일 읽어오기
백준 채점 환경은 리눅스 운영체제의 표준입력을 처리하기 때문에 /dev/stdin을 통해 파일처럼 읽기 작업을 처리한다.
백준 제출 전 풀이는 IDE를 통해 하기 때문에 기본적으로는 input.txt 파일에서 읽어오지만 제출 시(LINUX)라면 /dev/setdin을 통해 한다.
아래 fs모듈 선언, fs 파일 경로 설정 코드
const fs = require('fs');
const filePath = process.platform === 'linux' ? '/dev/stdin' : './input.txt';
2. 입력 처리
fs로 입력데이터를 받아왔고 이제 이 데이터를 원하는 형태로 가공해야 한다.
입력 데이터 원하는 형태로 가공하기
아래 코드보다 더 요약하는 방법도 있으나 기본적인 함수의 원리를 알고 사용하자!
0. 주로 쓰이는 함수
.toString() | 입력데이터를 문자열로 바꾸어줌 |
.trim() | 문자열 앞뒤 공백(space, tab, \n) 제거 |
.split(특정 문자) | 특정 문자 기준으로 나누고 각 부분을 요소로 가지는 배열 생성 |
1. 한 개 입력
가공 전 입력 데이터 | 가공 후(input) |
a | 'a' |
const fs = require('fs');
const filePath = process.platform === 'linux' ? '/dev/stdin' : './input.txt';
const input = fs.readFileSync(filePath).toString().trim();
2. 한 줄 입력
가공 전 입력 데이터 | 가공 후 (input) |
a b c | inpit = ['a', 'b', 'c'] |
const fs = require('fs');
const filePath = process.platform === 'linux' ? '/dev/stdin' : './input.txt';
const input = fs.readFileSync(filePath).toString().trim().split(' ');
3. 여러 줄 입력
가공 전 입력 데이터 | 가공 후(input) |
a b |
input = ['a', 'b'] |
const fs = require('fs');
const filePath = process.platform === 'linux' ? '/dev/stdin' : './input.txt';
const input = fs.readFileSync(filePath).toString().trim().split('\n');
4. 한 글자 + 한 줄
줄 바꿈으로 각 줄을 나누어 받고, 한 줄짜리는 공백으로 다시 나누어 문자열로 받음
가공 전 입력 데이터 | 가공 후(n, input) |
3 a b c |
n = 3 arr = ['a', 'b', 'c'] |
const fs = require('fs');
const filePath = process.platform === 'linux' ? '/dev/stdin' : './input.txt';
const input = fs.readFileSync(filePath).toString().trim().split('\n');
const n = parseInt(input[0]); // 첫 번째 줄은 숫자 n으로 저장
const arr = input[1].split(' ')
5. 한 글자 + 여러 줄
각 줄로 나누어 받고 0 인덱스를 제외하고 다시 배열을 구성함.
가공 전 입력 데이터 | 가공 후(n, input) |
3 a b c |
n = 3 arr = ['a', 'b', 'c'] |
6. 한 글자 + 여러 줄에서 여러 값 받아오기
가공 전 입력 데이터 | 가공 후(n, input) |
3 a b c d e f x y z |
n = 3 arr = [['a', 'b', 'c'], ['d', 'e', 'f'], ['x', 'y', 'z']] |
const fs = require('fs');
const filePath = process.platform === 'linux' ? '/dev/stdin' : './input.txt';
const input = fs.readFileSync(filePath).toString().trim().split('\n');
const n = +(input[0]);
const arr = input.slice(1).map(line => line.split(' '));
💫 입력받은 데이터를 숫자 이어야 하는 경우는. map(Number),. map(el => +el) 등을 사용할 수 있다.
readline 모듈을 사용해 입력받기
readline은 말 그대로 line을 통해 사용자가 입력한 값이 받아진다.
rl.close()가 실행되면 process.exit() 함수가 호출되면서 입력이 종료된다.
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
1. 한 줄 입력받기
가공 전 입력 데이터 | 가공 후(n, input) |
Hello world! | Hello world! |
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.on('line', function(line){
console.log(line);
rl.close();
}).on('close', function(){
process.exit();
})
2. 한 줄에 여러 개의 값 입력받기
가공 전 입력 데이터 | 가공 후(n, input) |
3 a b c d e f x y z |
n = 3 [['a', 'b', 'c'], ['d', 'e', 'f'], ['x', 'y', 'z']] |
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
let n; // 입력 줄 수를 저장할 변수
const arr = []; // 문자열 배열을 저장할 2차원 배열
rl.on('line', (line) => {
if (!n) {
n = parseInt(line); // 첫 번째 줄은 숫자 n으로 저장
} else {
arr.push(line.split(' ')); // 공백으로 분리하여 arr에 추가
if (arr.length === n) {
rl.close(); // 입력 종료
}
}
});