[BaekJoon] 15552번 - 빠른 A+B (java)

1. 문제

👉 문제 바로가기

- 조건

시간 제한 메모리 제한
1초 512MB


- 문제

본격적으로 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()을 추가로 해 주는 것이 좋다.
또한 입력과 출력 스트림은 별개이므로, 테스트케이스를 전부 입력받아서 저장한 뒤 전부 출력할 필요는 없다. 테스트케이스를 하나 받은 뒤 하나 출력해도 된다.



- 입력

첫 줄에 테스트케이스의 개수 T가 주어진다. T는 최대 1,000,000이다. 다음 T줄에는 각각 두 정수 A와 B가 주어진다. A와 B는 1 이상, 1,000 이하이다.



- 출력

각 테스트케이스마다 A+B를 한 줄에 하나씩 순서대로 출력한다.



- 예제

  입력      출력  
5
1 1
12 34
5 500
40 60
1000 1000
2
46
505
100
2000





2. 풀이

반복문 for를 사용해 첫 줄에 입력받은 값만큼 A + B를 반복한다.

for (초기식; 조건식; 증감식) {
    조건식의 결과가 참인 동안 반복적으로 실행하고자 하는 명령문 작성;
}




BufferedReader 입력방식과 2개의 출력방식을 사용해서 결과를 출력한다.

  1. BufferedWriter 클래스
  2. StringBuilder 클래스



- 2. BufferedWriter 클래스 사용

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.BufferedWriter;
import java.io.OutputStreamWriter;
import java.util.StringTokenizer;

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 num = Integer.parseInt(br.readLine()); 
      
        StringTokenizer st;

        for(int i=0;i<num;i++){
            st = new StringTokenizer(br.readLine()," ");
        
            int a = Integer.parseInt(st.nextToken()); 
            int b = Integer.parseInt(st.nextToken()); 
            bw.write(a+b+"\n");
        }
        br.close();
        bw.flush();
        bw.close();
    }
}

Integer.parseInt()을 사용해 readLine() 으로 읽어온 String형 데이터를 int형으로 변환시켜준다.

StringTokenizer 를 사용해 한 줄로 읽어온 데이터를 공백을 기준으로 분리하고, nextToken()을 이용해 순서대로 가져온다.

BufferedWriter 의 flush() 를 사용해 모아둔 데이터를 한번에 출력한다.



[여기서 잠깐!]

BufferedWriter 클래스에 대해 더 알아보고 싶으면 여기를 클릭하면 된다.





- 2. StringBuilder 클래스 사용

BufferedReader는 readLine() 메서드를 사용해 한 행을 전부 읽는다.
이를 공백단위로 분리해야 하는데, 두가지 분리 방법으로 문제를 풀어보자.



     ① StringTokenizer 클래스를 사용하여 분리해주는 방법
     ② split() 을 사용하는 방법



① StringTokenizer 클래스를 사용

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.util.StringTokenizer;

public class Main{
    public static void main(String[] args)throws IOException{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringBuilder sb = new StringBuilder();
        
        int num = Integer.parseInt(br.readLine()); 
      
        StringTokenizer st;

        for(int i=0;i<num;i++){
            st = new StringTokenizer(br.readLine()," ");
        
            int a = Integer.parseInt(st.nextToken()); 
            int b = Integer.parseInt(st.nextToken()); 
            sb.append(a+b).append("\n");
        }
        br.close();
        System.out.println(sb);
    }
}

readLine()은 한 줄을 통째로 읽어 String으로 반환하기 때문에 StringTokenizer 클래스를 사용해 “ “(공백)을 기준으로 값을 구분하고, nextToken()를 사용해 공백으로 구분된 입력값들을 순서대로 가져온다.

Integer.parseInt()을 사용해 String형을 int형으로 변환시켜준다.

StringBuilder 클래스는 문자열을 동적으로 조작하기 위한 클래스로, append() 를 사용해 문자열을 추가하여 새로운 문자열을 생성한다.

sb.append(a+b).append("\n");은 불필요한 문자열 연산을 하지 않고 StringBuilder에 직접 추가하기 때문에 sb.append(a+b+"\n"); 보다 더 효율적이고 빠르다.





② split() 을 사용

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));
        StringBuilder sb = new StringBuilder();
        
        int num = Integer.parseInt(br.readLine()); 
        
        String[] arr;
        
        for(int i=0;i<num;i++){
            arr = br.readLine().split(" "); 
        
            int a = Integer.parseInt(arr[0]); 
            int b = Integer.parseInt(arr[1]); 
            sb.append(a+b).append("\n");
        }
        br.close();
        System.out.println(sb);
    }
}

readLine()을 통해 한 줄로 받은 String 데이터를 split(" ") 메서드를 사용해 공백 단위로 나눈 뒤 배열에 저장한다.





3. BufferedWriter VS StringBuilder 성능 비교

image

출력의 경우 BufferedWriter 보다는 StringBuilder 가 빠른 것을 볼 수 있다.

아무래도 100만개 정도까지는 StringBuilder 가 근소하게 더 빠른 것 같다.
(그러나 데이터 양이 커지면 커질 수록 BufferedWriter 가 더 빠르다.)

BufferedWriter는 일반적으로 I/O 작업으로 인해 비교적 느릴 수 있다. 반면에 StringBuilder는 문자열 조작에 최적화된 클래스로, 문자열 연산은 일반적으로 메모리 상에서 수행되므로 상대적으로 빠를 수 있다.



4. StringTokenizer VS split() 성능 비교

image

문자열을 분리할 때, split() 메서드보다 StringTokenizer 가 더 빠르다.

StringTokenizer 클래스는 구분자를 단일 문자로 처리하기 때문에 복잡한 정규식을 사용할 필요가 없다. 그래서 문자열 분리에 대해서는 간단하고 빠른 성능을 보인다.

split() 메서드는 정규식을 사용하여 문자열을 분리하기 때문에, 정교한 정규식이 필요하거나 강력한 패턴 매칭이 필요할 때는 사용하는 것이 적절하다.





관련 페이지

Categories:

Updated:

Leave a comment