문제 정보
플랫폼 : 백준
분류 : 수학
난이도 : 브론즈2
링크 : https://www.acmicpc.net/problem/15552
풀이
이후에 풀이할 내용중에서 BufferedReader와 BufferedWriter라는 것을 사용할 때가 있다. 목적부터 말하자면, 빠른 입력과 빠른 출력이다. 가끔씩 Input Data를 몇십만, 몇백만건씩 받을 때가 있는데, 기존에 사용하던 Scanner 나 System.out.print를 사용하면 시간초과가 발생할 수 있다.
Scanner와System.out.print로 입출력을 했을 때 흐름도이다.BufferedReader, BufferedWriter를 사용했을 때 흐름도이다. 중간에 과정이 추가됐는데 왜 더 빠를까?
디스크IO 와 문맥 교환(Context Switching), 입출력은 생각보다 느린 작업이다. 당신이 키보드로 입력할 때마다 프로그램에 전달된다면, 오버헤드가 상당히 크게 발생한다. 당신이 키보드 입력을 끝낸 뒤에 한번에 전달되는게 더 빠를 것이다. 이해가 어렵다면, 예시를 들어보자.
당신이 마트에서 물건을 사려고 한다. 물건마다 진열대에서 계산대로 옮기는 것보다, 쇼핑카트에 모아뒀다가 한번에 계산대로 가져가는게 더 빠르다.
나는 보통 10만건 이상의 입력은 BufferedReader/Writer로, 미만은 Scanner로 받는다.
첫 번째 채점 결과는 BufferedReader, 두 번째 채점 결과는 Scanner로 받은 경우이다. Input Data는 T*10만건이다. (T는 테스트케이스의 갯수인데, 명시되어있진 않다.) Input방식만 바꿨을 뿐인데 두배가 넘는 시간 차이가 발생한다.
그러나 BufferedReader에도 단점이 있다.
1. IOException의 예외처리가 필수적이다.
2. 입력받은 모든 데이터가 String으로 반환된다.
3. 줄마다 입력받아서, 따로 split하여 데이터를 처리해주어야 한다.
4. 숫자형식으로 받기 위해서는 형변환이 필요하다.
이게 어떤 말이냐면, Input Data에 1 2 3이 들어왔다고 하자.
Scanner의 nextInt()로 받으면, [1, 2, 3]을 차례대로 받을 수 있다. 하지만 BufferedReader의 readLine()으로 받으면, "1 2 3"이라는 문자열 자체로 받으며, split(' ')로 띄어쓰기를 구분하여 Integer.parseInt() 과정이 필요해진다는 말이다.
이제 문제를 보자. 입력이 100만건이고, 시간제한은 1초이다. 일반적인 Scanner로 받으면 시간초과가 발생한다. BufferedReader를 사용해보도록 하자.
1. import는 java.io.*로 한다. (Scanner는 java.util 클래스이다.)
2. main함수 우측에 throws IOException을 통해 예외를 처리한다. (메소드 선언부에 throws를 명시하면, 해당 메소드 내에서 exception이 발생하는 경우 해당 메소드를 호출한 곳에서 예외가 발생한다.)
3. BufferedReader, BufferedWriter를 선언한다.
4. n을 입력받고, n만큼 loop를 돈다.
4-1. 해당 줄 전체를 String으로 입력받아, 스페이스로 구분하여 형변환하여 덧셈을 수행한다.
5. BufferedWriter에 써준다.
6. Buffer를 비워준다.
*여기서, bw.write()는 버퍼에 쓰는것이지, 화면에 출력되는 것이 아니다. 화면에 출력하는 역할은 bw.flush()가 수행한다. bw.flush()는 출력이 필요할 때 한 번만 수행해주면 된다. 만약 for문 안에 bw.flush()를 쓰면, 버퍼에 쓰고 바로 출력하므로 System.out.print와 다를바가 없다.
이전에 쇼핑카트 예제에서, 쇼핑카트에 물건 1개만 담고 계산대로 가져가고, 또 1개만 담고 계산대로 나르고... 하는것과 같은거다!
코드
import java.io.*;
class Main{
public static void main(String[] args) throws IOException{
BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
int n = Integer.parseInt(bf.readLine());
for(int i = 0; i < n; i++){
String s = bf.readLine();
int a = Integer.parseInt(s.split(" ")[0]);
int b = Integer.parseInt(s.split(" ")[1]);
bw.write(a+b+"\n");
}
bw.flush();
}
}
더 많은 정답 코드
블로그를 쓰기 이전에 풀어본 문제들이 많다. 해설강의는 없지만, 백준 문제의 풀이 코드가 필요한 경우 이곳을 클릭하여 소스코드를 참조해보도록 하자. 단, 코드만 복사-붙여넣기 하는것은 본인에게 결코 도움이 되지 않는다. 반드시 먼저 생각해보고, 막히는 경우에 참고하고 왜 이렇게 코드가 작성됐는지를 다시 한 번 생각해보는 습관을 들이자.