인트로
요즘 알고리즘 문제를 풀기 시작했다. 오랜만에 문제를 푸니 성능이 좋은 입출력 코드를 어떻게 작성하는지 기억이 나지 않았다.
특히 Scanner를 쓰면 시간초과가 나는 경우가 많다는 것은 알고 있었지만 `BufferedReader`와 `StringTokenizer`를 정확히 어떻게 사용해야 하는지 헷갈렸다. 그래서 이번 기회에 자바 알고리즘 입출력을 체계적으로 정리해서 포스팅하려고 한다.
Scanner는 왜 안 쓰는지, BufferedReader는 어떻게 쓰는지 차근차근 알아보자!
1. 왜 Scanner 말고 BufferedReader를 써야 할까?
// ❌ 이렇게 하면 시간초과 날 확률 높다
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
// ✅ 이렇게 해야 안전하다
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(br.readLine());
성능 차이: BufferedReader가 Scanner보다 빠르다!
왜 빠를까?
- BufferedReader: 데이터를 큰 덩어리로 한 번에 읽어서 버퍼(8192byte(8KB))에 저장한다
- Scanner: 매번 작은 단위(1024byte(1KB))로 읽고 파싱하는 과정이 많다.
- 띄어쓰기나 개행 문자 등을 기준으로 데이터를 분리해주는 편리한 기능이 있지만
- 그만큼 내부적으로 처리할 내용이 많아 성능이 느리다.
2. 알고리즘 문제의 기본 구조
대부분의 알고리즘 문제는 이런 형태이다.
첫째 줄에 정수 N이 주어진다.
둘째 줄에 N개의 정수가 공백으로 구분되어 주어진다.
이걸 자바로 받으면
int n = Integer.parseInt(br.readLine()); // 첫째 줄
StringTokenizer st = new StringTokenizer(br.readLine()); // 둘째 줄
int[] arr = new int[n];
for(int i = 0; i < n; i++) {
arr[i] = Integer.parseInt(st.nextToken());
}
패턴만 익히면 어떤 문제든 입력받을 수 있다!
3. 백준 문제 풀어보기 - A+B
백준 1000번 문제로 연습해보자!
문제: 두 정수 A와 B를 입력받은 다음, A+B를 출력하는 프로그램을 작성하시오.
import java.io.*;
import java.util.*;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
// "3 5" 같은 입력을 받아서 3과 5로 분리
StringTokenizer st = new StringTokenizer(br.readLine());
int A = Integer.parseInt(st.nextToken());
int B = Integer.parseInt(st.nextToken());
// 결과 출력
System.out.println(A + B);
}
}
Scanner 버전 (비추천)
Scanner sc = new Scanner(System.in);
int A = sc.nextInt();
int B = sc.nextInt();
System.out.println(A + B);
간단하지만 데이터가 많으면 시간초과 위험!
4. 기본 입력 패턴들
4-1. 숫자 하나 입력받기
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(br.readLine());
4-2. 한 줄에 여러 숫자 입력받기
// 입력: 3 5 7
StringTokenizer st = new StringTokenizer(br.readLine());
int a = Integer.parseInt(st.nextToken());
int b = Integer.parseInt(st.nextToken());
int c = Integer.parseInt(st.nextToken());
4-3. 배열 입력받기
// 입력: 1 2 3 4 5
int n = Integer.parseInt(br.readLine());
int[] arr = new int[n];
StringTokenizer st = new StringTokenizer(br.readLine());
for(int i = 0; i < n; i++) {
arr[i] = Integer.parseInt(st.nextToken());
}
4-4. 문자열 입력받기
String s = br.readLine();
5. 기본 출력 패턴들
5-1. 간단한 결과
System.out.println(answer);
5-2. 여러 줄 출력
StringBuilder sb = new StringBuilder();
for(int i = 0; i < n; i++) {
sb.append(result[i]).append('\n');
}
System.out.print(sb);
주의: println(sb) 말고 print(sb) 사용!
6. 예제 코드
import java.io.*;
import java.util.*;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
// 입력 처리
int n = Integer.parseInt(br.readLine());
// 출력 준비 (출력이 많을 때만)
StringBuilder sb = new StringBuilder();
// 로직 처리
// ...
// 결과 출력
System.out.println(answer); // 또는 System.out.print(sb);
}
}
7. 정리
꼭 기억할 것
- `import java.io.*;` 와 `import java.util.*;` 추가
- `throws IOException` 필수
- `BufferedReader br = new BufferedReader(new InputStreamReader(System.in));`
- 출력이 많으면 `StringBuilder` 사용
주의 사항
자바 공식 문서에 따르면 StringTokenizer는 "호환성을 위해 유지되는 레거시 클래스"이며
새로운 코드에서는 String.split() 사용을 권장한다.
하지만 알고리즘 문제에서는 성능상 이유로 StringTokenizer를 사용하는 경우도 있당
추천 연습 문제
- 백준 1000번 (A+B) - 기본 입출력 https://www.acmicpc.net/problem/1000
- 백준 2741번 (N 찍기) - 반복 출력 https://www.acmicpc.net/problem/2741
- 백준 8393번 (합) - 간단한 계산 https://www.acmicpc.net/problem/8393
8. 참고
- BufferedReader - Oracle Java SE 8 Documentation
- StringTokenizer - Oracle Java SE 8 Documentation
- StringBuilder - Oracle Java SE 8 Documentation
2편글 !!