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

Stranger's LAB

페이지 맨 위로 올라가기

Stranger's LAB

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

[백준] 2941번 : 크로아티아 알파벳 - JAVA [자바]

  • 2020.03.25 18:46
  • JAVA - 백준 [BAEK JOON]/문자열
글 작성자: ST_
728x90




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

 

2941번: 크로아티아 알파벳

문제 예전에는 운영체제에서 크로아티아 알파벳을 입력할 수가 없었다. 따라서, 다음과 같이 크로아티아 알파벳을 변경해서 입력했다. 크로아티아 알파벳 변경 č c= ć c- dž dz= đ d- lj lj nj nj š s= ž z= 예를 들어, ljes=njak은 크로아티아 알파벳 6개(lj, e, š, nj, a, k)로 이루어져 있다. 단어가 주어졌을 때, 몇 개의 크로아티아 알파벳으로 이루어져 있는지 출력한다. dž는 무조건 하나의 알파벳으로 쓰이고,

www.acmicpc.net







  • 문제



 

 



 

※ 주의할 점

  1. 크로아티아 알파벳의 개수를 세어야 한다.
  2. 배열로 풀 때 참조하려는 인덱스(index) 가 벗어나지 않는지 유의해야 한다.
  3. 8개의 문자는 특정 조건에 의해 변경되어 하나의 문자를 이루게 된다.






  • 2가지 입력방법을 이용하여 풀이한다.



Scanner 로 입력받아 연산하는 방법과 BufferedReader 로 입력받아 연산하는 방법, 두 가지 방법을 통해 풀이해보고자 한다.

 




  • 알고리즘

 


유의할 점은 알고리즘 설명에서는 의사코드(pseudocode)로 작성한다.

그래서 알고리즘에서 설명하는 코드를 백날 컴파일해봤자 에러만 뱉어낼것이다.

 

의사코드로 설명하는 이유는 행여나 자바가 아닌 다른 언어를 사용하는 경우에도 쉽게 자신이 쓰는 언어로 변경시킬 수 있도록 하기 위함이다.

의사코드로 작성하되, 기본 문법은 자바에 의거한다.

( charAt() 메소드를 쓰게 되는데 이 메소드는 문자열을 배열로 보고 해당 위치의 문자를 반환하는 메소드다. 시작값은 0 이다. )

 

 

 

 

1. 먼저 최대 100개의 글자로 이루어진 문자열 str 이 주어진다.

 

그리고 문자의 개수를 셀 변수 count 를 만들고 문자열에 대하여 문자열 길이만큼 반복할 반복문을 구성한다.

String str = input();
int count = 0;

for ( int i = 0; i < str.length; i++ ) { }

 

 

 

 

2. 이제 조건문을 작성해야한다.

예로들면 dz= 가 입력되면 dž 로 하나의 단어로 셀 수 있도록 해야하기 때문이다.

 

일단, 아래 변경될 문자 표를 다시 한 번 보자.

 

 

 

 

만약 참조하려는 문자가 c 를 입력받는다면 그 다음 문자를 참조하여 = 일 경우 č , - 일경우 ć 로 하나의 문자로 보는 것이다.

 

일단 c= 와 c- 가 있는 경우만 작성해보자면 아래와 같다.

 

String str = input();
int count = 0;

for (int i = 0; i < str.length; i++) {

	char ch = str.charAt(i);

	if(ch == 'c') {			// 만약 ch 가 c 라면?
		if(str.charAt(i + 1) == '=') {		//만약 ch 다음 문자가 '=' 이라면?
			// i+1 까지가 하나의 문자이므로 다음 문자를 건너 뛰기 위해 1 증가
			i++;		
		}
		else if(str.charAt(i + 1) == '-') {
			i++;
		}
	}
    
	count++;
    
}

 

즉, 만약 c= 와 c- 가 입력되어있다면 이를 하나의 문자로 보는 것이기 때문에

다음 반복문에서 = 이나 - 를 참조할 필요가 없다.

 

그렇기 때문에 해당 조건문을 만족하면 i 를 1 증가시켜 다음 문자를 건너 뛰게 해준다. 

그리고 해당 반복문이 종료될 때마다 count 변수를 1 증가 시킨다.

 

 

 

3. 그럼 c 뿐만 아니라 다른 조건들도 작성해주자.

참고로 dz= 는 3 개의 문자를 하나의 문자로 보기 때문에 i 를 2 를 증가시켜주어야 한다.

 

String str = input();
int count = 0;

for (int i = 0; i < str.length; i++) {

	char ch = str.charAt(i);

	if(ch == 'c') {			// 만약 ch 가 c 라면?
		if(str.charAt(i + 1) == '=') {		//만약 ch 다음 문자가 '=' 이라면?
			// i+1 까지가 하나의 문자이므로 다음 문자를 건너 뛰기 위해 1 증가
			i++;		
		}
		else if(str.charAt(i + 1) == '-') {
			i++;
		}
	}
    
	else if(ch == 'd') {
		if(str.charAt(i + 1) == 'z') {
			if(str.charAt(i + 2) == '=') {	// dz= 일 경우
				i += 2;
			}
		}
        
		else if(str.charAt(i + 1) == '-') {	// d- 일 경우
			i++;
		}
	}
    
	else if(ch == 'l') {
		if(str.charAt(i + 1) == 'j') {	// lj 일 경우
			i++;
		}
	}
    
	else if(ch == 'n') {
		if(str.charAt(i + 1) == 'j') {	// nj 일 경우
			i++;
		}
	}

	else if(ch == 's') {
		if(str.charAt(i + 1) == '=') {	// s= 일 경우
			i++;
		}
    }

	else if(ch == 'z') {
		if(str.charAt(i + 1) == '=') {	// z= 일 경우
			i++;
		}
	}
    
	count++;

}

print(count);

 

 

 

 

 

4. 완성이 된 것 같다.

마지막에 count 를 출력해주면 될까..?

 

이 알고리즘대로 작성해서 만들면 자바의 경우 다음과 같은 에러를 발견할 수 있을 것이다.

 

java.lang.StringIndexOutOfBoundsException

 

즉 인덱스 참조 범위를 벗어났다는 것이다. ( = 참조할 수 없는 범위 )

 

 

왜일까?

 

 

예로들어 이러한 문자를 받았다고 생각해보자.

 

aedzdz=ls=c

 

 

그림으로 보자면 다음과 같을 것이다.

 

 

 

 

한번 위의 알고리즘대로 하나씩 해보면 알 수 있을 것이다.

 

i 가 10 일 때 반복문을 생각해보자.

 

그럼 str.charAt(10) 을 통해 ch 에 저장되고 ( ch = 'c' )

c 라는 문자를 받았기 때문에 첫 번째 조건문을 실행시키게 된다.

 

그리고 여기서 문제가 발생한다.

if( str.charAt(i + 1) == '=' )

 

aedzdz=ls=c 이 문자열에서 마지막 c 다음의 문자는 존재 하지 않는다.

그런데 charAt() 을 통해 참조하려고 하니까 StringIndexOutOfBoundsException 이라는 에러를 뱉는 것이다.

 

 

해결방법은 무엇일까?

 

간단하다. 현재 i 의 값이 문자열 길이(str.length) 에서 -1 값보다 작을 경우에만 다음 조건문을 실행시키면 된다.

( dz= 를 검사할 때는 i 가 str.length - 2 보다 작아야한다. )

 

그럼 이를 토대로 각 조건문에 새로운 조건문들을 작성해보자.

 

String str = input();
int count = 0;

for (int i = 0; i < str.length; i++) {

	char ch = str.charAt(i);

	if(ch == 'c') {			// 만약 ch 가 c 라면?
		if(i < str.length - 1) {
			if(str.charAt(i + 1) == '=') {		//만약 ch 다음 문자가 '=' 이라면?
				// i+1 까지가 하나의 문자이므로 다음 문자를 건너 뛰기 위해 1 증가
				i++;		
			}
			else if(str.charAt(i + 1) == '-') {
				i++;
			}
		}
	}
    
	else if(ch == 'd') {
		if(i < str.length - 1) {
			if(str.charAt(i + 1) == 'z') {
				if(i < str.length - 2) {
					if(str.charAt(i + 2) == '=') {	// dz= 일 경우
						i += 2;
					}
				}
			}
        
			else if(str.charAt(i + 1) == '-') {	// d- 일 경우
				i++;
			}
		}
	}
    
	else if(ch == 'l') {
		if(i < str.length - 1) {
			if(str.charAt(i + 1) == 'j') {	// lj 일 경우
				i++;
			}
		}
	}
    
	else if(ch == 'n') {
		if(i < str.length - 1) {
			if(str.charAt(i + 1) == 'j') {	// nj 일 경우
				i++;
			}
		}
	}

	else if(ch == 's') {
		if(i < str.length - 1) {
			if(str.charAt(i + 1) == '=') {	// s= 일 경우
				i++;
			}
		}
    }

	else if(ch == 'z') {
		if(i < str.length - 1) {
			if(str.charAt(i + 1) == '=') {	// z= 일 경우
				i++;
			}
		}
	}
    
	count++;

}

print(count);

 

 

 

이러면 참조가 벗어나는 일이 없게 된다.

이런식으로 구조를 짜면 되겠다.

 

 

 




  • 풀이




- 방법 1 

import java.util.Scanner;

public class Main {
	public static void main(String[] args) {
    
		Scanner in = new Scanner(System.in);
        
		String str = in.nextLine();
        
		int count = 0;

		for (int i = 0; i < str.length(); i++) {

			char ch = str.charAt(i);

			if(ch == 'c') {			// 만약 ch 가 c 라면?
				if(i < str.length() - 1) {
					if(str.charAt(i + 1) == '=') {		//만약 ch 다음 문자가 '=' 이라면?
						// i+1 까지가 하나의 문자이므로 다음 문자를 건너 뛰기 위해 1 증가
						i++;		
					}
					else if(str.charAt(i + 1) == '-') {
						i++;
					}
				}
			}
		    
			else if(ch == 'd') {
				if(i < str.length() - 1) {
					if(str.charAt(i + 1) == 'z') {
						if(i < str.length() - 2) {
							if(str.charAt(i + 2) == '=') {	// dz= 일 경우
								i += 2;
							}
						}
					}
		        
					else if(str.charAt(i + 1) == '-') {	// d- 일 경우
						i++;
					}
				}
			}
		    
			else if(ch == 'l') {
				if(i < str.length() - 1) {
					if(str.charAt(i + 1) == 'j') {	// lj 일 경우
						i++;
					}
				}
			}
		    
			else if(ch == 'n') {
				if(i < str.length() - 1) {
					if(str.charAt(i + 1) == 'j') {	// nj 일 경우
						i++;
					}
				}
			}

			else if(ch == 's') {
				if(i < str.length() - 1) {
					if(str.charAt(i + 1) == '=') {	// s= 일 경우
						i++;
					}
				}
		    }

			else if(ch == 'z') {
				if(i < str.length() - 1) {
					if(str.charAt(i + 1) == '=') {	// z= 일 경우
						i++;
					}
				}
			}
		    
			count++;

		}

		System.out.println(count);
	}
}

 

 

가장 기본적인 방법이다.

 

알고리즘은 위에서 설명했던 알고리즘과 같게 했다.








- 방법 2 

 

 

BufferedReader 을 쓰는 방식이다.

 

그리고 위의 코드는 너무 복잡하니 조건문을 간략화하고 문자열의 길이를 변수로 바꿔서 좀 더 간략화 해보려 한다.

 

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

public class Main {
	public static void main(String[] args) throws IOException {
    
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		String str = br.readLine();
		
		int len = str.length();
		int count = 0;

		for (int i = 0; i < len; i++) {

			char ch = str.charAt(i);

			if(ch == 'c' && i < len - 1) {			// 만약 ch 가 c 라면?
				//만약 ch 다음 문자가 '=' 또는 '-' 이라면?
				if(str.charAt(i + 1) == '=' || str.charAt(i + 1) == '-') {		
					// i+1 까지가 하나의 문자이므로 다음 문자를 건너 뛰기 위해 1 증가
					i++;		
				}
				
			}
		    
			else if(ch == 'd' && i < len - 1) {
				if(str.charAt(i + 1) == '-') {	// d- 일 경우
						i++;
					}
				else if(str.charAt(i + 1) == 'z' && i < len - 2) {
					
					if(str.charAt(i + 2) == '=') {	// dz= 일 경우
						i += 2;
					}
				}
			}
		    
			else if((ch == 'l' || ch == 'n') && i < len - 1) {
				if(str.charAt(i + 1) == 'j') {	// lj 또는 nj 일 경우
					i++;
				}
			}
		    

			else if((ch == 's' || ch == 'z') && i < len - 1) {
				if(str.charAt(i + 1) == '=') {	// s= 또는z= 일 경우
					i++;
				}
			
		    }
		    
			count++;

		}

		System.out.println(count);
	}
}

 

 

위 코드를 실행하면 Scanner 보다 BufferedReader 가 속도가 빠르니 시간이 단축된다.

 

그리고 if 문에 문자열 변환에 있어 공통적인 점은 조건식으로 묶어서 괄호로 우선순위를 정해주면 된다.








  • 성능 차이

 

 


위에서 부터 순서대로

 

채점 번호 : 18673473  -  BufferedReader

채점 번호 : 18673470 -  Scanner

 

 

시간을 보면 BufferedReader 와 Scanner 의 성능차이 및 출력 방법에 따른 성능 차이 또한 볼 수 있다.

 







  • 정리

 


항상 필자가 강조하는 부분이지만 만약 문제를 딱 보고 한번에 완벽하게 구상되는 것이 아니라면 하나씩 차근차근 짜보면서 완성해나가는 것이 좋다.

 

필자 보통 코드를 짤 때 한 번에 완성이 안되면 완성시키기 위해 3 가지 방법을 쓴다.

1. 큰 틀부터 하나씩 짠다.

2. 예외가 발생하는 경우를 쭉 나열한다.

3. 예외를 처리하고 및 극단적인 경우의 값을 넣어 디버깅 해본다.

 

대강 위 3 가지를 거치면 적어도 에러가 나는 일은 많이 줄 것이다.





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

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

[백준] 1316번 : 그룹 단어 체커 - JAVA [자바]  (45) 2020.03.26
[백준] 5622번 : 다이얼 - JAVA [자바]  (29) 2020.03.24
[백준] 2908번 : 상수 - JAVA [자바]  (13) 2020.03.20
[백준] 1152번 : 단어의 개수 - JAVA [자바]  (33) 2020.03.20
[백준] 1157번 : 단어 공부 - JAVA [자바]  (42) 2020.03.19

댓글

이 글 공유하기

  • 구독하기

    구독하기

  • 카카오톡

    카카오톡

  • 라인

    라인

  • 트위터

    트위터

  • Facebook

    Facebook

  • 카카오스토리

    카카오스토리

  • 밴드

    밴드

  • 네이버 블로그

    네이버 블로그

  • Pocket

    Pocket

  • Evernote

    Evernote

다른 글

  • [백준] 1316번 : 그룹 단어 체커 - JAVA [자바]

    [백준] 1316번 : 그룹 단어 체커 - JAVA [자바]

    2020.03.26
  • [백준] 5622번 : 다이얼 - JAVA [자바]

    [백준] 5622번 : 다이얼 - JAVA [자바]

    2020.03.24
  • [백준] 2908번 : 상수 - JAVA [자바]

    [백준] 2908번 : 상수 - JAVA [자바]

    2020.03.20
  • [백준] 1152번 : 단어의 개수 - JAVA [자바]

    [백준] 1152번 : 단어의 개수 - JAVA [자바]

    2020.03.20
다른 글 더 둘러보기

정보

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_.

티스토리툴바