[백준] 11021번 : A+B - 7 - JAVA [자바]
https://www.acmicpc.net/problem/11021
-
문제
매우 간단한 문제다!
※ 주의할 점
- 첫 줄에 테스트 케이스 개수가 입력되고 다음 입력부터는 공백을 기준으로 두 개의 정수가 입력된다.
- "Case #n: " 문자열 뒤에 A+B 의 연산 결과값이 출력된다.
- 2가지 풀이방법을 제시한다.
Scanner 로 입력받아 연산하는 방법과 BufferedReader 로 입력받아 연산하는 방법, 두 가지 방법을 통해 풀이해보고자 한다.
또한 출력방법도 변경해보면서 성능을 최대화하여 시간을 단축해보고자 한다.
추가로 필자가 제출한 코드도 보여주고자 한다.
- 풀이
- 방법 1
import java.util.Scanner;
public class Main {
public static void main(String args[]) {
Scanner in = new Scanner(System.in);
int a = in.nextInt();
for (int i = 1; i <= a; i++) {
int c = in.nextInt();
int d = in.nextInt();
System.out.println("Case #" + i + ": " + (c + d));
}
in.close();
}
}
가장 기초적인 풀이 방법이다.
- 방법 2
BufferedReader 을 쓰는 방식이다.
readLine() 을 통해 입력 받아 연산하는 방법 두 가지를 설명할 것이다.
앞서 말했듯이 readLine() 은 한 행을 전부 읽기 때문에 공백단위로 입력해 준 문자열을 공백단위로 분리해주어야 문제를 풀 수 있을 것이다.
고로 문자열 분리는 StringTokenizer 을 사용할 것이다.
그리고 반드시 자료형 타입을 잘 보아야 한다.
st.nextToken() 은 문자열을 반환하니 Integer.parseInt()로 int 형으로 변환시켜준다.
또한 출력방법을 달리하여 풀이하는 방법 또한 알려줄 것이다.
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
import java.io.IOException;
public class Main {
public static void main(String args[]) throws IOException {
BufferedReader br= new BufferedReader(new InputStreamReader(System.in));
int a = Integer.parseInt(br.readLine());
StringTokenizer st;
for (int i = 1; i <= a; i++) {
st = new StringTokenizer(br.readLine()," ");
System.out.println("Case #" + i + ": "
+(Integer.parseInt(st.nextToken())
+Integer.parseInt(st.nextToken())));
}
br.close();
}
}
또 다른 출력 방법으로는 위 코드에서 StringBuilder 로 변경하여 쓰는 방법이다.
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
import java.io.IOException;
public class Main {
public static void main(String args[]) throws IOException {
BufferedReader br= new BufferedReader(new InputStreamReader(System.in));
int a = Integer.parseInt(br.readLine());
StringBuilder sb = new StringBuilder();
StringTokenizer st;
for (int i = 1; i <= a; i++) {
st = new StringTokenizer(br.readLine()," ");
sb.append("Case #").append(i).append(": ")
.append(Integer.parseInt(st.nextToken())
+Integer.parseInt(st.nextToken())).append('\n');
}
br.close();
System.out.println(sb);
}
}
물론 조금 더 복잡해졌긴 했다. 참고로 append 를 저렇게 나눠서 쓰는게 아닌 한 번에 써주어도된다.
sb.append("Case #"+ i + ": " + (Integer.parseInt(st.nextToken())+Integer.parseInt(st.nextToken())) + "\n" );
이런식으로 써주어도 된다. 근데 필자가 저렇게 나눠서 쓰는 이유는
직접 테스트해보면 알겠지만 저렇게 출력할 문자에 여러 타입이 섞여있으면 해당 메소드는 일일이 타입검사를 해주어야 하기 때문에 시간이 미약하게나마 더 걸리게 된다는 것이다. 물론 성능에 신경 안쓴다면 하나로 합쳐서 써도 무방하다.
또 다른 방법으로는 BufferedWriter 을 쓰는 방법이다.
아래 방법 또한 코드 자체는 복잡할지 몰라도 한 번 이해하면 써먹기 참 좋은 방법이다.
참고로 BufferedWriter.write() 메소드는 단독으로 int 형 값만 넣을경우 이는 아스키 코드값으로 인식되기 때문에 다른 문자가 나와버린다. 그러니 이를 방지하고 싶다면 반드시 문자열과 int 형을 함께 넣어줘야 int 값을 제대로 출력할 수 있다.
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
import java.io.IOException;
import java.io.BufferedWriter;
import java.io.OutputStreamWriter;
public class Main {
public static void main(String args[]) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
int a = Integer.parseInt(br.readLine());
StringTokenizer st;
for (int i = 1; i <= a; i++) {
st = new StringTokenizer(br.readLine()," ");
bw.write("Case #"+i+": ");
bw.write(Integer.parseInt(st.nextToken())
+Integer.parseInt(st.nextToken())+"\n");
}
br.close();
bw.flush();
bw.close();
}
}
- 더 좋은 방법 없을까?
시간을 최소화 하고싶다면 주어진 문제에서 최적의 알고리즘을 찾는 것이 중요하다.
문제를 잘 보자.
입력에서 A 와 B 의 범위는 0 초과 10 미만이다. 즉 1~9 사이라는 것이다.
그러면 문자열 분리할 때 공백이 들어가는 위치는 배열로 따질 때 다음과 같을 것이다.
A 와 B 는 "무조건" 한 자릿수만 입력받기 때문에 문자열로 입력받을시 공백이 들어가는 위치는 언제나 고정되어있다.
그럼 문자열의 특정 위치의 문자를 반환해주는 charAt() 을 쓸 수 있다면 StringTokenizer 객체를 계속 생성하지 않아도 되기에 시간이 더욱 단축 될 수 있을 것이다!
필자가 힌트를 주는 코드는 다음과 같다.
아래 코드를 보고 조금 더 고민해서 시간 단축을 할 수 있는 방법을 찾아 수정하면 충분히 상위권에 올라갈 수 있다.
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
public class Main {
public static void main(String args[]) throws IOException {
BufferedReader br= new BufferedReader(new InputStreamReader(System.in));
int a = Integer.parseInt(br.readLine());
StringBuilder sb = new StringBuilder();
for (int i = 1; i <= a; i++) {
String str = br.readLine();
sb.append("Case #").append(i).append(": ")
.append(str.charAt(0)-'0'+str.charAt(2)-'0').append('\n');
}
System.out.println(sb);
}
}
아 그리고 여러분들이 실수 할 수 있는 부분이 String.charAt() 은 해당 위치의 문자를 char 로 반환한다.
즉 만약 0이라는 문자열이 반환되면 아스키 코드값인 48이 반환된다.
이를 int형으로 연산하려고 하거나 문자 출력이 아닌 정수로 출력하려 하면 0 이라는 숫자가 아닌 48로 출력된다.
그러니 예로들어 문자 '6' 을 숫자 6 으로 바꾸고 싶다면 48을 빼주면 된다.
만약 몇을 빼줘야할지 모른다면 -'0' 으로 해도 된다.
- 성능 차이
위에서 부터 순서대로
채점 번호 : 17795732 - 필자 힌트 코드
채점 번호 : 17795715 - BufferedReader + BufferedWriter
채점 번호 : 17795699 - BufferedReader + StringBuilder
채점 번호 : 17795690 - BufferedReader + System.out.println()
채점 번호 : 17795680 - Scanner
위와같이 입력 메소드의 성능차이와 알고리즘 구현 방법에 따라 시간이 달라질 수 있음을 보여주고 있다.
- 정리
어떻게 해야 메소드 호출을 최소화하고 탐색을 적게 하는지, 기능이 같더라도 어느 메소드가 더 우월한지 검색해보고 비교해보면서 하나씩 체득해가다보면 문제를 풀면서 자연스럽게 "어느 것이 빠를 것 같다" 라는 느낌이 오게된다.
물론 필자 또한 완벽하게 장담할 수 있는 수준까지는 아니지만 적어도 대략적으로 어느 부분이 성능이 우수한지 알 수 있어서 문제를 푸는데 많은 도움이 되고 있다.
이렇게 배운 지식을 여러분들께 공유하고자 이 블로그를 시작했으니 많은 도움이 되었으면 좋겠다.
'JAVA - 백준 [BAEK JOON] > 반복문' 카테고리의 다른 글
[백준] 2438번 : 별찍기 - 1 - JAVA [자바] (8) | 2020.02.19 |
---|---|
[백준] 11022번 : A+B - 8 - JAVA [자바] (10) | 2020.02.19 |
[백준] 15552번 : 빠른 A+B - JAVA [자바] (34) | 2020.02.17 |
[백준] 8393번 : 합 - JAVA [자바] (5) | 2020.02.15 |
[백준] 10950번 : A+B - 3 - JAVA [자바] (14) | 2020.02.15 |