<1.8> 유효한 팰린드롬

mutexlocking·2022년 7월 8일
0

문제
: 입력한 문자열이 회문이면 "YES"를 , 회문이 아니면 "NO"를 출력하라
(이때 입력한 문자열은 알파벳 뿐만 아니라 다른 문자도 포함될 수 있으니,
이중 알파벳만을 가지고 회문을 검사하고, 그때 대소문자는 구분하지 말아라)

회문을 영어로 팰린드롬이라고 하는 만큼, 이 문제는 앞선 1.7 회문 문자열 문제와 거의 비슷하다. 즉 "입력한 문자열의 회문 여부 파악" 이 이 문제의 요구사항이라 할 수 있다.
다만 몇가지 핵심 요구사항은 유지한 채 , 한가지 조건이 더 추가되었다고 볼 수 있는데 바로 이것이다.

  • 입력한 문자열에 공백 - 특수문자를 포함한 알파벳이 아닌 문자가 섞여 있을 수 있음
    (문제상으로는 공백이 없는이라고 나와있지만, 채점시에도 공백이 포함된 문자열을 사용한 것을 보면 공백 포함이 맞는것 같음.)

이 조건이 추가됨에 따라 해결로직 또한 한가지 절차가 더 추가되었다.

1. 대소문자 구분을 무시하기 위해, 전체 문자열을 대문자로 변환

  • toUpperCase() 사용

2. 이후 문자열 중 대문자 알파벳만을 색출하여 별도의 문자열을 만듬
(추가된 로직)

: 이 부분에서 나와 , 선생님의 구현 방식에 차이가 있었다.
1) 나의 방식
: 일차원적으로 대문자로 변환한 문자열에 대해서, 대문자 알파벳의 아스키코드값이 65~90라는 점을 기반으로 하여 , 대문자 char만 추출하여 String으로 만듦.
-> 아스키코드값을 이용하여 직관적으로 생각할 수 있지만
-> String을 char배열로 변환 , 결과를 담을 또다른 char 배열, 이를 다시 String으로 변환 해야 하는 추가적인 작업이 필요함. (결국 코드 지저분)
2) 선생님 방식
: String 클래스의 replaceAll() 인스턴스 메서드를 사용하여 대문자만을 직관적으로 뽑아냄
-> 덕분에 코드가 직관적이게 됨. (가독성이 올라감)

3. 이후 만들어진 문자열을 뒤집고 , 기존 문자열과 같은지 여부로, 회문 여부 파악

  • StringBuilder 클래스의 reverse() 메서드 로 뒤집고
  • String 클래스의 오버라이딩 된 equals() 메서드로 문자열 일치 여부 판단

위 해결 로직에 따른 나의 코드와, 선생님의 코드는 아래와 같다.
i ) 내 코드

import java.util.Scanner;

public class Main {

    public static String solution(String str){

        //1_1. 전체 문자열을 일단 대문자로 통일
        /** 주목할 점: toUpperCase() 사용시 알아서 영어알파벳만 인식하여 대문자로 바꿔주고 , 그외 문자는 그냥 냅둔다.*/
        String upperStr = str.toUpperCase();

        //1_2. 이후 문자열을 char 배열로 변환
        char[] charArr = upperStr.toCharArray();

        //2_1. 각 문자별로 대문자만 추출하여 char 배열로 만들고
        char[] upperCharrArr = new char[charArr.length];
        int idx = 0;
        for (char c : charArr) {
            if(c>=65 && c<=90)
                upperCharrArr[idx++] = c;
        }

        // 이를 다시 String으로 변환
        String str1 = "";
        for(int i=0; i<idx; i++){
            str1 += upperCharrArr[i];
        }

        //3_1. 변환한 String을 역전시킨 문장을 만든 후
        String str2 = new StringBuilder(str1).reverse().toString();


        //3_2. 그 역전시킨 문장과 , 2_1 결과 문장이 일치하면 YES, 그렇지 않은면 NO를 리턴
        if(str1.equals(str2)) return "YES";
        else    return "NO";
    }

    public static void main(String[] args){
        //0. Scanner 준비
        Scanner sc = new Scanner(System.in);

        //1. 문자열 입력 (next()는 공백을 포함한 문자열을 입력받지 못하고 , nextLine()은 공백을 포함한 문자열을 입력받을 수 있다.)
        String str = sc.nextLine();

        //2. 입력받은 문자열을 인자로 넘기면서 solution()을 호출하여 , 유효한 팰린드롬인지 여부를 리턴받음
        String result = solution(str);

        //3. 리턴받은 결과를 출력
        System.out.println(result);
    }
}

ii) 선생님 코드

import java.util.Scanner;

public class Main2 {

    public static String solution(String str){
        //1. 알파벳만 인식하여 대문자로 변환시킨 후 -> replaceAll정규식을 이용하여 대문자가 아닌 문자는 빈문자로 대체 -> 즉 제거
        /** 주목할 점: toUpperCase() 사용시 알아서 영어알파벳만 인식하여 대문자로 바꿔주고 , 그외 문자는 그냥 냅둔다.*/
        String strOrigin = str.toUpperCase().replaceAll("[^A-Z]", "");

        //2. 이후 대문자만 남은 문자열을 역전
        String strReverse = new StringBuilder(strOrigin).reverse().toString();

        //3. 그 역전시킨 문장과 , 2_1 결과 문장이 일치하면 YES, 그렇지 않은면 NO를 리턴
        if(strOrigin.equals(strReverse)) return "YES";
        else    return "NO";

    }
    public static void main(String[] args) {
        //0. Scanner 준비
        Scanner sc = new Scanner(System.in);

        //1. 문자열 입력 (next()는 공백을 포함한 문자열을 입력받지 못하고 , nextLine()은 공백을 포함한 문자열을 입력받을 수 있다.)
        String str = sc.nextLine();

        //2. 입력받은 문자열을 인자로 넘기면서 solution()을 호출하여 , 유효한 팰린드롬인지 여부를 리턴받음
        String result = solution(str);

        //3. 리턴받은 결과를 출력
        System.out.println(result);
    }
}

이를 통해 새로 알게된 점, 또는 내가 기억해야할 점을 아래와 같이 정리하였다.

1. Scanner의 next()와 nextLine()의 차이

  • next()는 공백을 포함한 문자열을 입력받을 수 없고(공백 기준으로 잘림)
  • nextLine()은 공백을 포함한 문자열을 입력받을 수 있음.

2. String의 toUpperCase()메서드가 , 문자열을 대문자로 만드는 방식

  • 알파벳과 알파벳이 아닌 문자가 섞여 있어도
  • 그중에서 알파벳만을 대문자로 변환한다. (확인해보았음)

3. String값 + String이 아닌 값의 덧셈 (+ 기호 사용)

  • String이 아닌 값이 String이 되어 , 기존 String뒤에 concat()으로 이어붙여진다.
  • String에 char 문자값이 더해지는게 모호했는데, 바로 이 동작방식 덕분에 무사히 문자열로 만들어 지는 것 같다.

4. String 클래스의 인스턴스 메서드로써 replace()와 replaceAll() 이란게 지원된다.

  • replace("param1", "param2")
    : 해당 문자열에서 "param1"을 찾아서 "param2"로 대체한다
    -> 이때 "param2"가 ""로 빈 문자열이면 -> 해당 'param1" 부분이 없어진다.
  • replaceAll("param1", "param2")
    : 해당 문자열에서, "param1"에 해당하는 정규직이 의미하는 불특정 문자열을 전부 - "param2"로 대체한다. (""인경우 모두 없어짐)
    -> 이때 선생님이 사용하진 "[^A-Z]" 라는 정규식은 "A부터 Z까지의 대문자가 아닐 경우" 를 의미하고
    -> 이에 따라 "A부터 Z까지의 대문자가 아닌 나머지 문자들은 전부 지워진다."
    -> 이 정규식에 대해서 추후 더 공부할 필요가 있다.
profile
개발자가 되고자 try 하는중

0개의 댓글