이 영역을 누르면 첫 페이지로 이동
Stranger's LAB 블로그의 첫 페이지로 이동

Stranger's LAB

페이지 맨 위로 올라가기

Stranger's LAB

프로그래밍과 관련하여 다양한 알고리즘 문제를 풀어보고, 프로그래밍 언어를 이해해 볼 수 있도록 돕고자 만든 블로그 입니다.

[백준] 10951번 : A+B - 4 - JAVA [자바]

  • 2020.02.24 11:57
  • JAVA - 백준 [BAEK JOON]/반복문
글 작성자: ST_
728x90




https://www.acmicpc.net/problem/10951

 

10951번: A+B - 4

두 정수 A와 B를 입력받은 다음, A+B를 출력하는 프로그램을 작성하시오.

www.acmicpc.net

 

 

 





  • 문제




 



간단한 문제지만 의외로 종료시점을 몰라 틀리는 경우들이 많은 것 같다.



※ 주의할 점

  1. 두 정수는 공백으로 나뉘어 구분된다.
  2. 입력의 종료는 더이상 읽을 수 있는 데이터 (EOF) 가 없을 때 종료한다.

 

 

 

 





  • 3가지 방법을 사용하여 풀이한다.

 

 

 

 

먼저 입력 방식의 차이를 두어 Scanner 로 입력받아 연산하는 방법과 BufferedReader 로 입력받아 연산하는 방법, 두 가지 방법으로 풀어볼 것이고, 나머지 하나는 문자열 분리 방법에 차이를 두어 풀어 볼 것이다.

즉 다음 3가지로 풀어볼 것이다.

 

  1. Scanner
  2. BufferedReader + StringTokenizer (문자열 분리)
  3. BufferedReader + String.charAt()

 

 

 





  • EOF 란?

 

 


이 문제에서 가장 중요한 점이 파일 종료 조건이 없이 그냥 입력이 주어졌다는 것이다.

즉 입력에서 더이상의 읽을 수 있는 데이터가 존재하지 않을 때 반복문을 종료하라는 것이다.

 

이렇게 데이터가 더이상 존재하지 않을 때 우리는 EOF (End of File) 즉, 파일의 끝이라 한다.

 

이를 처리하는 방법은 입력의 종류에 따라 여러 방법이 있다. 우리는 그 중 Scanner 와 BufferedReader 두 개의 처리 방법을 알아보고자 한다.



  •  Scanner  


Scanner 의 메소드들의 경우 더이상 읽을 데이터가 없으면 아래 사진과 같이 
NoSuchElementException 을 던지게 된다.

 


보다시피 Scanner 에 읽을 데이터가 없으면 아래와 같이 예외를 던져버린다.

 

이렇게 던져진 예외의 경우 두 가지 방법이 있다.

  1. try-catch 문으로 예외발생시 반복문을 종료해주도록 처리함.
  2. Scanner 의 메소드인 hasNext() 를 통해 처리해준다. 


위의 방법 중에 우리는 hasNext() 라는 메소드를 이용할 것이다. 



※ 주의할 점

 백준 알고리즘에서는 데이터를 주는 과정에서 더이상의 데이터를 보내지 않음으로 NoSuchElementException 을 발생 시킬 수 있다. 그러나 우리가 평상시에 입력받는 방법인 System.in, 즉 키보드로 입력받을 경우 Scanner 는 우리가 흔히 쓰는 Enter, Space 도 입력 예외를 발생시키지 않는다. 쉽게 말하면 데이터로 무언가를 받아들인단 소리다.

 

우리가 평상시에 입력받는 방식으로 예외처리를 하려면 \n 을 입력받거나 " "(공백) 을 입력받을 경우의 조건문을 걸어 예외를 발생시켜 종료시켜야하지만, 백준 문제처럼 파일 입력의 경우는 종료시점에서 더이상 데이터를 보낼 수가 없기 때문에 예외가 발생된다.

 

특히 hasNext(), hasNextInt() 등 이런 메소드들로 처리해도 백준에서는 문제가 해결되는 이유가 더이상 데이터를 읽을 것이 없는경우 당연히 nextInt() 에서 받는 입력이 존재하지 않아 예외를 던져준다.

 

그러나 IDE나 터미널에서 우리가 입력을 할 경우 공백이나 엔터를 치더라도 이 또한 입력 이벤트로 데이터가 스트림에 넣어지는 것이기 때문에 예외가 던져지는 것이 아니다. 결국 반복문을 종료시키려면 hasNextInt()에서 EOF를 입력(윈도우의 경우는 ctrl + Z, 리눅스계열의 경우 ctrl + D)해주거나 정수가 아닌 문자열을 입력한다던가 등 다른 타입의 입력을 주어 InputMismatchException 을 던져주어야 한다.





위에 보면 2번째 빈 칸은 공백(space)를, 4번째엔 Enter 를 쳤지만 예외가 발생하지 않는 걸 볼 수 있다.

예외를 발생시켜 프로그램을 종료시키기 위해 정수가 아닌 값을 입력함으로써 예외를 발생시켜야 종료될 수 있음을 보여줬다.

 

 

 

 

  • BufferedReader


BufferedReader 의 경우 null 을 반환한다. 이 부분은 오히려 null 인지 아닌지만 조건문을 통해 구분해주면 되므로 쉽다.

참고로 BufferedReader로 null을 반환하기 위해서는 역시 EOF를 던져주어야 하기 때문에 ctrl + Z (윈도우)혹은 ctrl + D(리눅스)를 입력해야한다.

 

 

 

 

 




 

 

  • 풀이

 

 




- 방법 1 

import java.util.Scanner;

public class Main {
	public static void main(String args[]){
		
		Scanner in=new Scanner(System.in);
			
		while(in.hasNextInt()){
		
			int a=in.nextInt();
			int b=in.nextInt();
			System.out.println(a+b);
		
		}	
		in.close();
	}
}

 

 

 

가장 기초적인 방법이다.

 

이 문제에서는 hasNextInt(), hasNext() 둘 중 아무거나 써도 괜찮다. 어차피 입력이 아예 들어오지 않기 때문에 예외가 발생하는 형태는 같기 때문이다.

그래도 nextInt() 를 통해 정수를 입력받고자 했으니 hasNextInt() 를 써주는게 다른 코딩할 때도 착오가 발생하지 않는다.

 

참고로 hasNextInt() 의 경우 입력값이 정수일경우 true를 반환하며 정수가 아닐경우 바로 예외를 던지며 더이상의 입력을 받지 않고 hasNextInt()에서 false를 반환하면서 반복문이 종료된다.

 





 





 

 

- 방법 2 

 

 


BufferedReader 을 쓰는 방식이다.

 

readLine() 을 통해 입력 받아 연산하는 방법을 설명할 것이다.

앞서 말했듯이 readLine() 은 한 행을 전부 읽기 때문에 공백단위로 입력해 준 문자열을 공백단위로 분리해주어야 문제를 풀 수 있을 것이다.



문자열 분리 방법에는 두 가지 방법이 있다.

  1. StringTokenizer 클래스를 이용하여 분리해주는 방법
  2. split() 을 이용하는 방법

필자는 StringTokenizer를 선호하는 편이다. 특정 상황이 아니면 성능면에서 훨씬 우월하기 때문이다.

고로 이 문제에서도 StringTokenizer 을 쓸 것이다. 또한 출력에서는 StringBuilder 을 쓸 것이다.

참고로 반드시 자료형 타입을 잘 보아야 한다.

st.nextToken() 은 문자열을 반환하니 Integer.parseInt()로 int 형으로 변환시켜준다.

 



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();
		StringTokenizer st;
		String str;

		while( (str=br.readLine()) != null ){
		    
			st = new StringTokenizer(str," ");
			int a = Integer.parseInt(st.nextToken());
			int b = Integer.parseInt(st.nextToken());
			sb.append(a+b).append("\n");
		
		}
		System.out.print(sb);
	}
}

 

 

 

위 코드에서 보다시피 readLine() 을 통해 입력을 하여 str 에 저장된 데이터가 null 일 경우 while 반복문을 종료시켜버리고 아닐경우 반복문을 계속 수행하도록 한다.

 

 

 

 

 






 

 

- 방법 3



 

뭔가 StringTokenizer가 성능이 좋다고는 하지만 반복문을 할 때마다 객체를 계속 생성해주는게 시간을 잡아먹을 것 같지 않은가?

 

여기서 문제를 잘 보면 입력되는 정수는 반드시 ( 0< A,B < 10 ) 이다. 즉, 한자릿수 정수만 입력받는다.

그렇게 되면 자연스레 공백(" ")의 위치도 항상 고정된 위치라는 것을 알 수 있다.

 

그러면 굳이 객체생성을 안하고 더욱 쉽고 빠르게 짤 수 있지 않을까?

당연히 있다. charAt()을 써보자.

 

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();
		String str;

		while( (str=br.readLine()) != null ){
		    
			int a = str.charAt(0) - 48;
			int b = str.charAt(2) - 48;
			sb.append(a+b).append("\n");
		
		}
		System.out.print(sb);
	}
}

 

 

더욱 간결해진 느낌이다.

몇 번 언급했지만 charAt() 은 해당 문자의 아스키코드 값을 반환하기 때문에 반드시 우리가 아는 정수 형태로 변경하려면 -48 또는 -'0'을 해주어야 한다.

 

위와같이 짜면 더 빠르냐고 묻는다면 아래 성능 차이를 보면 된다.

 

 

 

 

 




 

 

  • 성능 차이




 

 



 

 

위에서 부터 순서대로

 

채점 번호 : 17903361  -  BufferedReader + String.charAt()

채점 번호 : 17903348  -  BufferedReader + StringTokenizer

채점 번호 : 17903335  -  Scanner

 

시간을 보면 BufferedReader 와 Scanner 의 성능차이가 확연하게 나는 것을 볼 수가 있다.

또한 반복적인 객체 생성보다는 String.charAt() 메소드 호출이 더 빠르다는 것을 볼 수 있다.

 

 

여러분께 도움되는 글이니 꼭 한 번씩 테스트 해보시길 권한다.

 

 

 










  • 정리

 

 

 

 

 

EOF 에 대해서 간단하게 알아보았다.

 

사실 A+B 계열 문제는 워낙 많이 풀어왔으니 알고리즘 자체는 어렵지 않았을 것이고, 입력이 더이상 주어지지 않을 때 어떻게 처리해야하는지를 배운 것이 이 포스팅의 가장 큰 소득이 아닐까 싶다.



 

 

 

 

 

저작자표시 비영리 변경금지 (새창열림)

'JAVA - 백준 [BAEK JOON] > 반복문' 카테고리의 다른 글

[백준] 1110번 : 더하기 사이클 - JAVA [자바]  (36) 2020.02.26
[백준] 10952번 : A+B - 5 -JAVA [자바]  (21) 2020.02.23
[백준] 2439번 : 별 찍기 - 2 - JAVA [자바]  (6) 2020.02.19
[백준] 2438번 : 별찍기 - 1 - JAVA [자바]  (8) 2020.02.19
[백준] 11022번 : A+B - 8 - JAVA [자바]  (10) 2020.02.19

댓글

이 글 공유하기

  • 구독하기

    구독하기

  • 카카오톡

    카카오톡

  • 라인

    라인

  • 트위터

    트위터

  • Facebook

    Facebook

  • 카카오스토리

    카카오스토리

  • 밴드

    밴드

  • 네이버 블로그

    네이버 블로그

  • Pocket

    Pocket

  • Evernote

    Evernote

다른 글

  • [백준] 1110번 : 더하기 사이클 - JAVA [자바]

    [백준] 1110번 : 더하기 사이클 - JAVA [자바]

    2020.02.26
  • [백준] 10952번 : A+B - 5 -JAVA [자바]

    [백준] 10952번 : A+B - 5 -JAVA [자바]

    2020.02.23
  • [백준] 2439번 : 별 찍기 - 2 - JAVA [자바]

    [백준] 2439번 : 별 찍기 - 2 - JAVA [자바]

    2020.02.19
  • [백준] 2438번 : 별찍기 - 1 - JAVA [자바]

    [백준] 2438번 : 별찍기 - 1 - JAVA [자바]

    2020.02.19
다른 글 더 둘러보기

정보

Stranger's LAB 블로그의 첫 페이지로 이동

Stranger's LAB

  • Stranger's LAB의 첫 페이지로 이동

검색

나의 외부 링크

  • st-github

공지사항

  • 공지 - 블로그 사용 설명서

메뉴

  • 홈
  • 방명록

카테고리

  • 전체 카테고리 (267)
    • Java (5)
    • JAVA - 백준 [BAEK JOON] (177)
      • 입출력과 사칙연산 (14)
      • 조건문 (7)
      • 반복문 (11)
      • 1차원 배열 (7)
      • 함수 (3)
      • 문자열 (10)
      • 기본 수학 1 (8)
      • 기본 수학 2 (6)
      • 2차원 배열 (0)
      • 정렬 (10)
      • 재귀 (4)
      • 브루트 포스 (5)
      • 집합과 맵 (0)
      • 기하 1 (5)
      • 정수론 및 조합론 (12)
      • 백트래킹 (8)
      • 동적 계획법 1 (15)
      • 누적 합 (0)
      • 그리디 알고리즘 (5)
      • 스택 (5)
      • 큐, 덱 (7)
      • 분할 정복 (9)
      • 이분 탐색 (7)
      • 기타 문제 (17)
      • 별 찍기 문제 모음 (2)
    • C++ - 백준 [BAEK JOON] (46)
      • 입출력과 사칙연산 (14)
      • 조건문 (7)
      • 반복문 (11)
      • 1차원 배열 (7)
      • 함수 (3)
      • 문자열 (0)
      • 기타 문제 (4)
    • 자료구조 (18)
      • Java (18)
    • 알고리즘 (11)
      • Java (11)
    • 프로그래밍 기초 (6)
    • 이모저모 (2)
    • 일상의 글 (2)

최근 글

정보

ST_의 Stranger's LAB

Stranger's LAB

ST_

블로그 구독하기

  • 구독하기
  • 네이버 이웃 맺기
  • RSS 피드

방문자

  • 전체 방문자
  • 오늘
  • 어제

티스토리

  • 티스토리 홈
  • 이 블로그 관리하기
  • 글쓰기
Powered by Tistory / Kakao. Copyright © ST_.

티스토리툴바