1157번: 단어 공부
알파벳 대소문자로 된 단어가 주어지면, 이 단어에서 가장 많이 사용된 알파벳이 무엇인지 알아내는 프로그램을 작성하시오. 단, 대문자와 소문자를 구분하지 않는다.
www.acmicpc.net
문제
알파벳 대소문자로 된 단어가 주어지면, 이 단어에서 가장 많이 사용된 알파벳이 무엇인지 알아내는 프로그램을 작성하시오. 단, 대문자와 소문자를 구분하지 않는다.
입력
첫째 줄에 알파벳 대소문자로 이루어진 단어가 주어진다. 주어지는 단어의 길이는 1,000,000을 넘지 않는다.
출력
첫째 줄에 이 단어에서 가장 많이 사용된 알파벳을 대문자로 출력한다. 단, 가장 많이 사용된 알파벳이 여러 개 존재하는 경우에는 ?를 출력한다.
코드
import java.io.*;
import java.util.HashMap;
import java.util.Map;
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));
String str = br.readLine();
// 알파벳 별 등자 횟수를 저장할 맵
Map<Character, Integer > hashMap = new HashMap<>();
// 문자열에서 알파벳만 추출하여 처리
char[] characters = str.replaceAll("[^a-zA-Z]]", "").toUpperCase().toCharArray();
// 알파벳 별로 등장 횟수를 맵에 기록
for(char ch : characters){
hashMap.put(ch, hashMap.getOrDefault(ch, 0) + 1);
}
char maxAlphabet = ' ';
int maxCount = 0;
for(Map.Entry<Character, Integer> entry : hashMap.entrySet()){
if(entry.getValue() > maxCount){
maxAlphabet = entry.getKey();
maxCount = entry.getValue();
} else if (entry.getValue() == maxCount){
maxAlphabet = '?';
}
}
bw.write(maxAlphabet);
bw.flush();
}
}
(1) BufferedReader 및 BufferedWriter 사용
...
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
String str = br.readLine();
...
1. 성능 향상 : 입출력 스트림에 직접 접근하는 것보다 해당 클래스 사용 시 데이터를 효율적으로 읽고 쓸 수 있음
2. 버퍼링 : 내부적으로 데이터를 임시로 저장하는 버퍼를 사용하고 있음, 덕분에 작은 데이터를 읽고 쓰는 경우에도 전체 파일이나 스트림을 매번 읽지 않아도 되기 때문에 효율성이 증가함
3. 문자 및 라인 단위 처리: BufferedReader은 문자 단위이므로 BufferedWriter은 문자 또는 라인 단위로 데이터를 처리할 수 있음, 따라서 행 단위로 텍스트 데이터를 읽고 쓰는데 편리함
결론: BufferedReader, BufferedWriter 사용 시 입출력 성능을 향상시키고, 데이터를 효율적으로 처리하는 데에 도움을 준다.
(2) HashMap, 알파벳 추출, 대문자 변환
...
// 알파벳 별 등자 횟수를 저장할 맵
Map<Character, Integer> hashMap = new HashMap<>();
// 문자열에서 알파벳만 추출하여 처리
char[] characters = str.replaceAll("[^a-zA-Z]]", "").toUpperCase().toCharArray();
// 알파벳 별로 등장 횟수를 맵에 기록
for(char ch : characters){
hashMap.put(ch, hashMap.getOrDefault(ch, 0) + 1);
}
...
1. Map<Character, Integer> 을 사용한 이유는?
- 알파벳의 등장 횟수를 효율적으로 추적하기 위해서이다. 여러 알파벳이 등장한 횟수를 카운트 하는 상황에서 HashMap은 알파벳을 키(key)로 가지고, 등장 횟수를 값(value)로 매핑하여 저장하는데 효율적이기 때문이다.
2. char[] characters
- 위에서 입력한 문자열 str를 각 알파벳 별로 나눠 맵에 저장하기 위해 문자열 배열인 characters를 선언했다.
0 [^a-zA-Z] 는 알파벳이 아닌 모든 문자에 일치하는 정규 표현식이다. 여기서 replaceAll("[^a-zA-Z]", "")는 정규표현식에 일치라는 모든 문자를 빈 문자열로 대체하여 제거하자는 뜻이다. 결과적으로는 "알파벳만 추출하자."라는 뜻..
- 이렇게 추출한 문자열을 toUpperCase() 메서드를 통해 모두 대문자로 변환한 다음, toCharArray() 메서드를 통해 문자열을 문자 배열로 변환하여 characters[]에 저장했다.
3. forEach()
- 알파벳 별로 등장 횟수를 기록하고자, forEach를 통해 처리했다.
- hashMap.getOrDefault(ch, 0) + 1 은 현재 알바펫이 이미 맵에 등록되어 있다면, 해당 횟수를 가져오고, 등록되어 있지 않다면 0으로 초기화하여 1을 더한 값을 맵에 저장하자는 뜻이다.
3. 가장 많이 사용된 알파벳 추출
...
char maxAlphabet = ' ';
int maxCount = 0;
for (Map.Entry<Character, Integer> entry : hashMap.entrySet()) {
if (entry.getValue() > maxCount) {
maxAlphabet = entry.getKey();
maxCount = entry.getValue();
} else if (entry.getValue() == maxCount) {
maxAlphabet = '?';
}
}
...
1. HashMap에 저장된 각 알파벳의 등장 횟수를 확인하고, 그 중에서 가장 많이 등장한 알파벳을 찾는 부분이다.
2. maxAlphabet 변수에는 가장 많이 등장한 알파벳이 저장되며, maxCount 는 해당 알파벳의 등장 횟수가 저장된다.
3. forEach()
- 여기서 사용된 for 루프는 hashMap의 각 항목을 순회하며 찾는 역할을 한다.
- 먼저 Map.Entry< , > 를 통해 hashMap에 저장된 각 key-value 쌍을 순회하면서 각각의 키와 값을 출력할 수 있다.
- hashMap.entrySet()을 통해 앞의 Map.Entry 의 Set을 반환한다.
- 결과적으로 entry는 for루프를 통해 각 반복에서 현재 순회중인 Map.Entry 객체를 나타내는 변수라고 생각하면 된다.
4. if() else if()
- 만약 현재 알파벳 등장 횟수가 maxCount보다 크면, maxAlphabet과 maxCount를 현재 알바펫과 해당 횟수로 갱신한다.
- 만약 현재 알파벳 등장 횟수가 maxCount와 동일하다면, maxAlphabet을 '?'로 설정한다.
결과
메모리나 시간을 생각보다 많이 잡아먹은 것 같다 ..
정답인 코드는 없다지만 .. 이보다 더 간단한 방법을 고려해야겠다. 😖
예컨대 문자의 인코딩 값을 이용하는 방법도 좋은 해결책인 것 같다.
'Algorithm' 카테고리의 다른 글
[BOJ/Java] 2941 크로아티아 알파벳 (0) | 2023.12.08 |
---|