경진 프로그래밍(Competitive Programming)을 Java로 입문한 많은 사람이 Scanner 클래스를 사용한 입력처리 때문에 TLE(Time Limit Exceeded)를 보게된다. 느린 Scanner가 엄청나게 큰 입력을 빠르게 처리하지 못해서 발생하는 문제이다.
입력으로 인한 TLE 발생을 해결하기 위해서는 BufferedReader와 StringTokenizer 클래스의 조합을 이용하면 된다. Scanner는 적은 코드로 쉽게 입력을 처리할 수 있지만 입력 데이터를 받아들인 후 정규식을 사용하여 원시타입(Primitive Type)과 문자열로 파싱하기 때문에 느리다. 반면에 BufferedReader 클래스는 문자 입력 스트림으로부터 텍스트를 읽어들여 버퍼에 저장하고 사용자가 필요에 맞춰 StringTokenizer를 이용하여 원하는 타입으로 파싱하기 때문에 빠르다. Scanner도 버퍼를 가지고 있긴 하지만 1KB로 BufferedReader의 8KB에 비하면 작다.
BufferedReader 사용시의 단점은 코드가 길어진다는 것이다. 하지만 C/C++에 비교할만한 빠른 입력 속도를 얻을 수 있고 아래 코드의 FastIo 클래스처럼 재사용 가능한 형태로 작성해두면 필요시마다 복사해 사용할 수 있으니 이점에 비해 큰 단점은 아니라고 생각한다.
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.StringTokenizer;
public class Main {
public static void main(String[] args) {
FastIo io = new FastIo();
int k = io.nextInt();
long[] a = new long[k];
for (int i=0; i<k; i++) {
a[i] = io.nextLong();
}
for (int i=0; i<k; i++) {
io.write(a[i] + " ");
}
io.write("\n");
io.flush();
io.close();
}
static class FastIo {
BufferedReader br;
BufferedWriter bw;
StringTokenizer s;
FastIo() {
br = new BufferedReader(new InputStreamReader(System.in));
bw = new BufferedWriter(new OutputStreamWriter(System.out));
}
String next() {
while (s == null || !s.hasMoreTokens()) {
try {
s = new StringTokenizer(br.readLine());
} catch (IOException e) {
e.printStackTrace();
}
}
return s.nextToken();
}
int nextInt() {
return Integer.parseInt(next());
}
long nextLong() {
return Long.parseLong(next());
}
void write(String s) throws IOException {
bw.write(s);
}
void flush() throws IOException {
bw.flush();
}
void close() throws IOException {
bw.close();
}
}
}