문제
앞에서 읽을 때나 뒤에서 읽을 때나 같은 문자열을 팰린드롬이라고 합니다.
문자열이 입력되면 해당 문자열이 팰린드롬이면 "YES", 아니면 “NO"를 출력하는 프로그램을 작성하세요.
단 회문을 검사할 때 알파벳만 가지고 회문을 검사하며, 대소문자를 구분하지 않습니다.
알파벳 이외의 문자들의 무시합니다.
입력
첫 줄에 길이 100을 넘지 않는 공백이 없는 문자열이 주어집니다.
출력
첫 번째 줄에 팰린드롬인지의 결과를 YES 또는 NO로 출력합니다.
입력 예시 1
found7, time: study; Yduts; emit, 7Dnuof
출력 예시 1
YES
아이디어
우선 해당 문제에서 가장 중요한 핵심은 "알파벳 이외는 문자는 어떻게 무시하는가?" 입니다. 이번 글에서는 총 두 개의 방식을 소개해보려고 합니다.
첫 번째로 StringTokenizer 클래스를 이용하는 방식입니다. StringTokenizer는 문자열을 토큰 단위로 구분하고자 할 때 많이 쓰이는데요 아마 제 글에서는 Scanner 클래스 보다 BufferedReader 클래스를 많이 다루니 자주 보시게 될 것 같습니다.
+ Scanner와 다르게 BufferedReader는 라인 단위로 입력 받습니다. 따라서 부득이하게 공란이 생길 경우에는 파싱이 필수적입니다.
StringTokenizer는 구분자를 설정할 수 있습니다.
예를 들어, StringTokenizer st = new StringTokenizer("Hello!World", "!"); 라는 구문이 있을 때 "Hello", "World" 라는 두 토큰이 생깁니다.
후에 자세히 StringTokenizer에 대해서 포스팅 하도록 하겠습니다.
본론으로 돌아와서 저는 이 구분자를 이용해 알파벳 이외는 문자를 다 무시하도록 구현하였습니다.
코드
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine(), " `~1@#$%^&*()-=_+,./<>?;':[]{}");
boolean isPelindrome = true;
String str = "";
while (st.hasMoreTokens()) {
str += st.nextToken();
}
str = str.toUpperCase();
for (int i = 0; i < str.length(); i++) {
if (str.charAt(i) != str.charAt(str.length() - 1 - i)) {
isPelindrome = false;
break;
}
}
if (isPelindrome)
System.out.print("YES");
else System.out.print("NO");
}
}
우선 위의 StringTokenizer 코드를 보시면 키보드 상에 존재하는 모든 특수문자를 구분자로 쓰고자 하였습니다. 해당 코드로 인해 입력 받은 문자열에서 특수 문자를 기점으로 파싱되게 됩니다.
위의 예제 입력을 기반으로 말씀드리면 found7 time study Yduts emit 7Dnuof 이 토큰으로 나누어지겠네요.
만약 문제에서 "대소문자를 구분하지 않는다" 라고 명시하였다면 대소문자를 통일해주는 것이 좋습니다. 따라서 toUpperCase() 메소드를 통해 문자열을 대문자로 통일해주었습니다.
그 다음으로 파싱된 문자열들을 다시 하나의 문자열로 통합해주는 과정을 거쳤습니다. while 반복문을 사용하였는데, 이는 토큰이 남아있을 때 까지 계속해서 반복되게 됩니다.
그렇게 하나의 문자열로 통합되었다면 charAt() 메소드를 통해 앞과 뒤의 문자를 순차적으로 검사해줍니다. 만약 문자가 같지 않다면 탈출 한 후 불리안 변수에 false 값이 저장되게 됩니다.
하지만 위 코드에는 치명적인 단점이 있습니다. 만약 구분자 중에서 특수문자를 하나라도 빠트리면 오류를 야기할 수 있기 때문입니다.
두 번째 방법은 replaceAll() 메소드를 이용하는 방법입니다.
코드
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().toUpperCase().replaceAll("[^A-Z]", "");
boolean isPelindrome = true;
for (int i = 0; i < str.length(); i++) {
if (str.charAt(i) != str.charAt(str.length() - 1 - i)) {
isPelindrome = false;
break;
}
}
if (isPelindrome)
System.out.print("YES");
else System.out.print("NO");
}
}
앞 전의 코드와 매우 유사하지만 알파벳 이외의 문자들을 걸러내는 과정이 다릅니다.
이번에는 문자열 입력과 동시에 toUpperCase()로 대문자로 통일한 뒤, replaceAll() 메소드를 이용하여 A-Z를 제외한 나머지 문자를 다 공백으로 변환하였습니다.
여기서 중요한 건 toUpperCase()와 replaceAll()의 위치입니다.
아스키 코드를 공부하신분은 아시겠지만 a-z 와 A-Z 사이에는 여러 특수문자가 존재합니다. 막연하게 a-Z 를 replaceAll에 넣으면 제대로 변환이 안되는 것이지요.
따라서 먼저 문자열을 대문자로 변환 시킨 뒤 A-Z가 아닌 (^) 것 들을 공백으로 치환해줍니다.
'Algorithm' 카테고리의 다른 글
[Baekjoon] 1766 문제집 with Java (0) | 2023.05.10 |
---|---|
[Inflearn] 가장 짧은 문자거리 with Java (2) | 2023.01.05 |
[Inflearn] 문자 찾기 with Java (0) | 2023.01.03 |
DFS, BFS with Java (0) | 2022.09.14 |
다익스트라(Dijkstra) 알고리즘 with Java (0) | 2022.09.14 |
댓글