[백준] 10809번 : 알파벳 찾기 - JAVA [자바]
https://www.acmicpc.net/problem/10809
10809번: 알파벳 찾기
각각의 알파벳에 대해서, a가 처음 등장하는 위치, b가 처음 등장하는 위치, ... z가 처음 등장하는 위치를 공백으로 구분해서 출력한다. 만약, 어떤 알파벳이 단어에 포함되어 있지 않다면 -1을 출력한다. 단어의 첫 번째 글자는 0번째 위치이고, 두 번째 글자는 1번째 위치이다.
www.acmicpc.net
-
문제
문제의 난이도는 어렵지 않다.
※ 주의할 점
- 입력으로 주어지는 문자열은 알파벳 소문자로만 이루어져 있다.
- a ~ z 를 모두 출력하여 주어진 문자열에 대해 해당 문자가 처음으로 나오는 위치를 출력한다.
- 위치는 0 부터 시작한다. 즉 문자열 첫 단어는 위치가 0 이다.
- 2가지 풀이 방법을 제시한다.
먼저 Scanner 로 입력받아 연산하는 방법과 BufferedReader 로 입력받아 연산하는 방법, 두 가지 방법을 통해 풀이해보고자 한다.
- 알고리즘
1. 먼저 int 형 배열을 하나 생성하여 모두 -1 로 초기화 시킨다.
이 배열은 문자열 S 에 각 문자의 위치를 가리킬 배열이다.
int[] arr = new int[26];
for(int i = 0; i < arr.length; i++){
arr[i] = -1;
}
2. S 이라는 문자열이 주어진다.
int[] arr; // -1 로 초기화 된 배열
String S = in.nextLine();
3. 그리고 반목문을 통해 문자열의 각 문자를 검사하여야 한다. 즉, charAt() 이라는 메소드를 사용하여 문자를 추출한 뒤 ch 라는 변수에 저장해준다.
int[] arr; // -1 로 초기화 된 배열
String S = in.nextLine();
for(int i = 0; i < S.length(); i++){
char ch = S.charAt(i);
}
5. 그리고 ch 의 문자의 위치를 우리가 앞서 만든 arr 배열의 값으로 바꿔준다.
이때 문제에서 위치는 0 부터 시작한다고 했으니 ch 의 문자의 위치는 i 가 되는 것을 알 수 있다.
또한 arr 배열의 인덱스(원소 위치)는 ch 가 갖고 있는 문자 인코딩 값(=아스키코드 값과 동일)에 'a' 또는 97 을 빼주면 된다.
( a 는 10진수로 97 이라는 값에 대응된다.)
만약 b 라는 문자가 ch 에 담겨있을 경우 b - 'a' 또는 b - 97 을 하면 1 이 되고, arr[1] 은 문자 b를 가리키는 것을 의미한다.
즉 아래와 같이 짜면 된다.
int[] arr; // -1 로 초기화 된 배열
String S = in.nextLine();
for(int i = 0; i < S.length(); i++){
char ch = S.charAt(i);
arr[ch - 'a'] = i;
}
6. 근데 문제가 있다. 문제를 잘 보면 동일 문자가 포함되어있는 경우 처음 나타난 위치로 나타내야한다.
즉, 문자열을 앞에서부터 검사할 때, 앞선 동일문자가 존재하여 arr 에 위치를 변경했을 경우는 arr 의 값을 변경하지 않으면 된다.
이 의미는 결국 -1 인 경우에는 배열의 원소 값을 변경하고 -1 이 아닌 경우 배열의 원소 값을 변경하지 않는다.
즉, 조건문을 추가하여 아래와 같이 짜면 된다.
int[] arr; // -1 로 초기화 된 배열
String S = in.nextLine();
for(int i = 0; i < S.length(); i++) {
char ch = S.charAt(i);
if(arr[ch - 'a'] == -1) { // arr 원소 값이 -1 인 경우에만 초기화
arr[ch - 'a'] = i;
}
}
이런식으로 구조를 짜면 된다.
그럼 전체 코드를 한 번 보자.
- 풀이
- 방법 1
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int[] arr = new int[26];
for(int i = 0; i < arr.length; i++) {
arr[i] = -1;
}
String S = in.nextLine();
for(int i = 0; i < S.length(); i++) {
char ch = S.charAt(i);
if(arr[ch - 'a'] == -1) { // arr 원소 값이 -1 인 경우에만 초기화
arr[ch - 'a'] = i;
}
}
for(int val : arr) { // 배열 출력
System.out.print(val + " ");
}
}
}
위의 알고리즘을 토대로 그대로 구현한 코드다.
그리고 한 줄에 한 원소와 한 공백씩 출력해야한다는 거 유의하자.
- 방법 2
BufferedReader 을 쓰는 방식이다.
입력에 있어 성능이 매우 뛰어나서 필자가 매우 좋아하는 입력방법 중 하나다.
알고리즘은 변경하지 않고 방법 1 의 코드에서 입력 방법만 바꾼 코드다.
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[] arr = new int[26];
for(int i = 0; i < arr.length; i++) {
arr[i] = -1;
}
String S = br.readLine();
for(int i = 0; i < S.length(); i++) {
char ch = S.charAt(i);
if(arr[ch - 'a'] == -1) { // arr 원소 값이 -1 인 경우에만 초기화
arr[ch - 'a'] = i;
}
}
for(int val : arr) { // 배열 출력
System.out.print(val + " ");
}
}
}
- 성능 차이
위에서 부터 순서대로
채점 번호 : 18519553 - BufferedReader
채점 번호 : 18519538 - Scanner
알고리즘의 수행시간은 O(N) 이다. 나름 빠른 알고리즘에 속하지 않을까 싶다만.. 더 좋은 코드드도 많을테니 한 번 직접 구상해보시는 걸 추천한다. 시간을 보면 BufferedReader 와 Scanner 의 성능차이를 볼 수 있다.
- 정리
보면 아주 단순한 문제다.
다만 보면 가끔 이중 for문을 취하는 분들도 많이 계신데, 나쁜 방법은 아니나 수행시간에 있어 그다지 좋지 못하다.
최대한 가능하다면 반복수행을 최소화 하는 방향으로 구성하는게 가장 좋은 방법이다.
'JAVA - 백준 [BAEK JOON] > 문자열' 카테고리의 다른 글
[백준] 1152번 : 단어의 개수 - JAVA [자바] (33) | 2020.03.20 |
---|---|
[백준] 1157번 : 단어 공부 - JAVA [자바] (42) | 2020.03.19 |
[백준] 2675번 : 문자열 반복 - JAVA [자바] (22) | 2020.03.19 |
[백준] 11720번 : 숫자의 합 - JAVA [자바] (15) | 2020.03.17 |
[백준] 11654번 : 아스키 코드 - JAVA [자바] (6) | 2020.03.16 |