java - 15552번 : 빠른 A+B(2024-01-06)
1. 서론
반복문(for문)을 풀면서 이러한 문제를 만나게 된다.
문제
본격적으로 for문 문제를 풀기 전에 주의해야 할 점이 있다. 입출력 방식이 느리면 여러 줄을 입력받거나 출력할 때 시간초과가 날 수 있다는 점이다.
C++을 사용하고 있고 cin/cout을 사용하고자 한다면, cin.tie(NULL)과 sync_with_stdio(false)를 둘 다 적용해 주고, endl 대신 개행문자(\n)를 쓰자. 단, 이렇게 하면 더 이상 scanf/printf/puts/getchar/putchar 등 C의 입출력 방식을 사용하면 안 된다.
Java를 사용하고 있다면, Scanner와 System.out.println 대신 BufferedReader와 BufferedWriter를 사용할 수 있다. BufferedWriter.flush는 맨 마지막에 한 번만 하면 된다.
Python을 사용하고 있다면, input 대신 sys.stdin.readline을 사용할 수 있다. 단, 이때는 맨 끝의 개행문자까지 같이 입력받기 때문에 문자열을 저장하고 싶을 경우 .rstrip()을 추가로 해 주는 것이 좋다.
또한 입력과 출력 스트림은 별개이므로, 테스트케이스를 전부 입력받아서 저장한 뒤 전부 출력할 필요는 없다. 테스트케이스를 하나 받은 뒤 하나 출력해도 된다.
자세한 설명 및 다른 언어의 경우는 이 글에 설명되어 있다.
이 블로그 글에서 BOJ의 기타 여러 가지 팁을 볼 수 있다.
입력
첫 줄에 테스트케이스의 개수 T가 주어진다. T는 최대 1,000,000이다. 다음 T줄에는 각각 두 정수 A와 B가 주어진다. A와 B는 1 이상, 1,000 이하이다.
출력
각 테스트케이스마다 A+B를 한 줄에 하나씩 순서대로 출력한다.
예제 입력 1 복사
5
1 1
12 34
5 500
40 60
1000 1000
예제 출력 1 복사
2
46
505
100
2000
(출처 - https://www.acmicpc.net/problem/15552)
뭣????
여태까지 Scanner로 잘 풀다가 낯선이가 나타났다;;;
2. 본론
여태까지 풀고 찾아보고 chat GPT에게 물어본 결과 3가지 방법을 알 수 있었다.
1. Scanner를 이용하는 방법
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("테스트 케이스 입력");
int T = sc.nextInt();
for(int i=1; i<=T; i++) {
int A = sc.nextInt();
int B = sc.nextInt();
System.out.println(A+B);
}
sc.close();
}
}
<결과>
뭔가 입력받고 출력하기 가장 쉬운 방법이다.
2. BufferedReader와 BufferedWriter 사용하기(StringTokenizer 사용하기)
BufferedReader는 Scanner의 역할을 대신한다 라고 생각된다.
BufferedWriter는 System.out.println();의 역할을 대신한다 라고 생각된다.
StringTokenizer는 문자열(String)을 토큰화한다, 나눈다(Token)정도로 생각해볼 수 있다.
먼저 BufferedReader와 BufferedWriter를 선언해준다.
// BufferedReader를 간단하게 말하자면 Scanner와 같은 역할을 한다고 생각됩니다.
// BufferedReader는 Enter키를 경계로 인식합니다.
// BufferedWriter를 간단하게 말하자면 System.out.print와 같은 역할을 한다고 생각됩니다.
// BufferedReader, BufferedWriter의 선언
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
//이것을 선언함으로서 키보드로 치는 것을 받아들입니다.
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
//이것을 선언함으로서 BufferedReader로 받아들인 것을 출력합니다.
BufferedReader와 BufferedWriter는 문자열(String)에만 적용되기 때문에 따로 형변환을 해주어야 한다.
System.out.println("테스트 케이스 입력");
// String T = br.readLine(); << 문자열일 경우, 그냥 이렇게 사용하면 됩니다.(BufferedReader로 받아들이는 것들은 보통 문자열입니다.)
int T = Integer.parseInt(br.readLine()); // << 형변환을 해주어야 합니다.
BufferedReader와 BufferedWriter은 입출력 작업을 수행하고 br.readLine()과 후에 나올 bw.write는 입출력 작업에 해당하는데 이는 작업 중에 예외가 발생할 수 있다. 그래서 예외를 던질 처리(throws IOException)를 해주어야 한다. 이제 까지 코드를 정리하면 다음과 같다.
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 Buffered {
public static void main(String[] args) throws IOException {
// BufferedReader를 간단하게 말하자면 Scanner와 같은 역할을 한다고 생각됩니다.
// BufferedReader는 Enter키를 경계로 인식합니다.
// BufferedWriter를 간단하게 말하자면 System.out.print와 같은 역할을 한다고 생각됩니다.
// BufferedReader, BufferedWriter의 선언
BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); //<<이것을 선언함으로서 키보드로 치는 것을 받아들입니다.
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out)); //<<이것을 선언함으로서 BufferedReader로 받아들인 것을 출력합니다.
System.out.println("테스트 케이스 입력");
// String T = br.readLine(); << 문자열일 경우, 그냥 이렇게 사용하면 됩니다.(BufferedReader로 받아들이는 것들은 보통 문자열입니다.)
int T = Integer.parseInt(br.readLine()); // << 숫자형식일 경우, 문자형인 br.readLine()를 정수형, 실수형으로 변환해줄 필요가 생깁니다.
}
}
이제 입력된 테스트 케이스 만큼 반복해야 한다.
for(int i=1;i<=T;i++) {
StringTokenizer st = new StringTokenizer(br.readLine()); //<< StringTokenizer는 말 그래도 문자열(String)을 토큰화(Tokenizer)합니다.
// 토큰화 라는 것은 split과 같은 역할을 한다고 볼 수 있겠습니다. 구분자가 많을 때 사용할 수 있을거라 생각합니다.
// 혹은 수식을 애매하게 알고 있을 때 사용하면 좋을 거라 생각됩니다.
int A = Integer.parseInt(st.nextToken());
int B = Integer.parseInt(st.nextToken());
bw.write(A + B + "\n");
}
bw.flush();
bw.close();
br.close();
BufferedWriter를 통해 버퍼를 잡아 뒀으니 flush와 close를 사용하여 버퍼에 있는 것을 모두 내보내고 종료시키고,
BufferedReader를 통해 버퍼를 잡아 뒀으니 close를 통해 종료시켜야 한다.
종합하면 이런 코드가 된다.
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 Buffered {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
System.out.println("테스트 케이스 입력");
int T = Integer.parseInt(br.readLine());
for(int i=1;i<=T;i++) {
StringTokenizer st = new StringTokenizer(br.readLine());
int A = Integer.parseInt(st.nextToken());
int B = Integer.parseInt(st.nextToken());
bw.write(A + B + "\n");
}
bw.flush();
bw.close();
br.close();
}
}
<결과>
여기서 "\n"에 대한 것은 개행문자라고 한다. 적용하지 않으면 출력값이 개행되지 않고 한줄로 출력될 것이다.
3. BufferedReader와 BufferedWriter 사용하기(sprit 사용하기)
StringTokenizer의 코드와 전체적으로 유사하지만 반복문 내에서 다르게 적용된다.
// 이건 StringTokenizer을 사용하지 않았을 때
String[] input = br.readLine().split(" ");
// 1. String[] input << String[] input String형(문자열) 배열을 생성합니다. 그리고 input 변수로 정의합니다.
// 2. br.readLine() << 키보드로 타이핑 되는 것을 받아들입니다.
// 2-1. .split(" "); 키보드로 타이핑 되는 것을 받아들이는데 배열에 넣기 위해서 구분이 필요합니다. split을 통해 공백(스페이스키)으로 구분합니다.
int A = Integer.parseInt(input[0]);
// input변수가 문자열(String)이기 때문에 정수형으로 변환해주는 작업이 필요하고, 공백(스페이스키)입력 전까지의 데이터를 받아들여 input배열 0번째칸에 넣습니다.
int B = Integer.parseInt(input[1]);
// input변수가 문자열(String)이기 때문에 정수형으로 변환해주는 작업이 필요하고, 공백(스페이스키)입력 후 데이터를 받아들여 input배열 1번째칸에 넣습니다.
// Enter키를 누르면 첫번째 반복문이 끝납니다.
코드를 종합하면 다음과 같다.
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
public class Buffered {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
System.out.println("테스트 케이스 입력");
int T = Integer.parseInt(br.readLine());
for(int i=1;i<=T;i++) {
String[] input = br.readLine().split(" ");
int A = Integer.parseInt(input[0]);
int B = Integer.parseInt(input[1]);
bw.write(A + B + "\n");
}
bw.flush();
bw.close();
br.close();
}
}
<결과>
3. 결론
쉬운 길로만 가고자 하는 주인장이라 Scanner를 애용할거 같지만....굳이 BufferedReader,Writer를 사용할거면?
StringTokenizer를 사용할거 같다.