코딩테스트/프로그래머스

[Java] 프로그래머스 Level 2 : 모음사전

이덩우 2023. 6. 29. 11:19

- 문제설명

- 예시

- 해결과정

  • 규칙성을 알아보고자 반복작업을 해보았다.

  • 글자의 개수에 맞춰 번호가 지정되는 것도 아니고 문자별 번호에 대한 규칙을 찾기 어려웠다.
  • 모음사전에 따르면,  "A"는 1번이고 "I"는 예시처럼 1563번이다. 
  • 둘의 번호 차이는 1562이고, 그럼 각 문자로 시작하는 모든 경우의 수는 781개가 된다.
  • 어떻게 781개가 됐을까?

  • 아하! "I"가 1563번인 이유는, I -> E로 바뀌기 위해 (1+5+25+625)번 소요되고, E -> A로 바뀌기 위해(1+5+25+625)번이 소요되구나 생각할 수 있었다. 근데, 지금 계산으로는 781 + 781 = 1562인데 실제 "I"는 1563이다. 
  • 모든 자리를 A로 만들어 직전의 경우 "A"를 만들었다. "A"를 만드는데 까지 걸린 횟수는 1562회다.
  • 하지만 "A"자체가 1번 ~ "AAAAA"는 5번이기 때문에 모든것을 A로 만들고, 해당 경우의 번호까지 더해줘야 마무리가 된다.

  • 확신이 안서는가? 예시를 몇 가지 더 확인해보자.

  • 이제 코드로 작성만 하면 된다.
  • 아래와 같은 순서로 코드를 작성했다.
    1. 입력 문자열에서, A,E,I,O,U -> 1,2,3,4,5로 매핑시켜서 배열로 저장했다.
    2. 재귀함수를 만들었다. 만든 배열과 임의의 인덱스를 인자로 받아서, 해당 인덱스의 문자를 A로 바꾸기 까지 과정을 만들었다. 문자를 숫자로 매핑시켜놔서 재귀의 한 단계를 거칠 때마다 숫자를 하나씩 내리는 방식으로 설계했다.
    3. 배열의 최대 크기가 5이므로, 메인문에서 재귀함수를 인덱스 0~4까지 총 5번 호출한다.
    4. 입력 문자열의 길이가 5보다 작을 수 있으므로, 인덱스별 재귀를 5번 호출해주는 과정에서 ArrayIndexOutOfBoundsException이 발생할 수 있다. 배열의 범위를 넘어가는 자릿수는 건드릴 필요가 없다! 예외처리는 공백으로 두면 된다.

- 솔루션

import java.util.*;
class Solution {
    public int solution(String word) {
        int answer = 0;
        int[] arr = word.chars()
                .mapToObj(c -> (char) c)
                .mapToInt(c -> {
                    switch (c) {
                        case 'A':
                            return 1;
                        case 'E':
                            return 2;
                        case 'I':
                            return 3;
                        case 'O':
                            return 4;
                        case 'U':
                            return 5;
                        default:
                            return 0;
                    }
                })
                .toArray();    // "AAAAE" -> [1,1,1,1,3] 처럼 변경     
        try {
            answer += arr.length;
            answer += recursion(arr, 0, 0);
            answer += recursion(arr, 0, 1);
            answer += recursion(arr, 0, 2);
            answer += recursion(arr, 0, 3);
            answer += recursion(arr, 0, 4);
        } catch (ArrayIndexOutOfBoundsException e) {}
        return answer;
    }
    
    private int recursion(int[] arr, int sum, int index) {
        if(arr[index] == 1) return sum; 

        if(index == 0) sum += 781;
        if(index == 1) sum += 156;
        if(index == 2) sum += 31;
        if(index == 3) sum += 6;
        if(index == 4) sum += 1;
        arr[index]--;
        
        return recursion(arr, sum, index);
    }
}

- 정리

  • String에서 문자 하나 하나를 쪼개 스트림을 만들때, chars()를 통해 IntStream을 먼저 만들게 된다.
  • chars()를 썻는데 왜 정수형스트림이 생길까 참 의문이지만, 직접적으로 바로 문자형 스트림을 만들 수 없다고 한다.
  • chars()를 통해 정수형 스트림 생성 --> mapToObj(c -> (char) c)를 통해 정수를 문자로 변환
  • 위 과정을 거쳐야 문자열을 하나 하나 쪼개서 스트림을 만들 수 있었다.
  • 재밌는 문제였다!