ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • BOJ) 암호코드 (2011 번)
    알고리즘/백준 2021. 1. 26. 18:54
    반응형

    암호코드

     

    2011번: 암호코드

    나올 수 있는 해석의 가짓수를 구하시오. 정답이 매우 클 수 있으므로, 1000000으로 나눈 나머지를 출력한다. 암호가 잘못되어 암호를 해석할 수 없는 경우에는 0을 출력한다.

    www.acmicpc.net

     

    문제의 조건이 많이 주어지지 않아서, 예외 케이스를 많이 찾아야했다.

    우선, 문제를 살펴보면 문자를 숫자로 암호화하는데, A=1, Z=26으로 암호화를 한다.

    이 암호화된 숫자로부터 나올 수 있는 암호의 경우의 수를 구하는 문제다.

    암호를 만들 수 없는 경우는 0을 출력한다는 조건도 있다.

     

    먼저, 입력받을 때 부터 예외 케이스를 검증해주었다.

    0으로 시작하는 경우, 연속으로 0이 들어오는 경우, 입력한 문자열이 빈 문자열인 경우, 숫자가 아닌 문자열이 들어오는 경우를 먼저 체크해주었다.

     

    1) 0으로 시작하는 경우

    위의 조건인 1~26 어떤 수에도 부합하지 않는다.

     

    2) 연속으로 0이 들어가는 경우

    10023 이라는 숫자가 있다고 한다면, 처음 시작은 10으로 시작된다. (1의 경우, 다음 문자인 0이 부합하지 않음)

    10 다음 숫자에 대해서 문자로 복호화를 해주어야하는데, 0이라는 숫자가 위의 조건에 부합하지 않는다.

     

    3) 빈 문자열인 경우

    복호화할 문자가 없음

     

    4) 숫자가 아닌 문자열이 들어오는 경우

    로직 자체에서 해석을 할 수 없음(예외 발생)

     

    경우의 수를 구하는 자체는 어렵지 않다.

    먼저, 포인터를 움직이면서 현재 가리키는 문자가 0인 경우, 복호화할 문자가 없기 때문에 이외의 경우에 이전 문자열까지 구해왔던 경우의 수를 저장해준다.

    다음으로는 경우의 수가 추가되는 문자인지 확인해준다.

    예를 들어, 앞서 1이라는 문자에 대해서 복호화를 해주었는데, 이번 포인터가 2를 가리킨다면 1과 12 둘 다 복호화할 수 있는 경우기 때문에 현재 포인터의 두번 앞선(i -2) 경우의 수를 더해준다.

     

     

     

    코드

     

    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.util.List;
    import java.util.regex.Pattern;
    
    public class SecretCode_2011 {
        private final static int MOD = 1000000, MIN = 1, MAX = 26, NUMBER_ASCII_START = 48, NUMBER_ASCII_END = 57;
        private final static String WRONG_INPUT = "0", CONTINUITY_ZERO = ".*0{2,}.*";
    
        public static void main(String[] args) throws IOException {
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
            String inputStr = br.readLine();
            StringBuilder sb = new StringBuilder();
    
            if(isValidInput(inputStr)) {
                sb.append(solution(inputStr.toCharArray()));
            } else {
                sb.append(WRONG_INPUT);
            }
            br.close();
    
            System.out.println(sb.toString());
        }
    
        private static int solution(char[] numArr) {
            int len = numArr.length;
            int[] dp = new int[len+1];
            dp[0] =1;
    
            if(len ==1) {
                return numArr[0] == NUMBER_ASCII_START ? 0 : dp[0];
            }
    
            for(int i=1; i<=len; i++) {
                int prev = i-2;
                int now = i-1;
    
                if(numArr[now] != '0') { // 현재 pointer가 0이라면, 만들 수 있는 암호(경우의 수)가 없음
                    dp[i] = dp[now];
                }
                if(prev <0) { // out of range 방지
                    continue;
                }
                if(isValidPermutation(numArr[prev], numArr[now])) { // 연속으로 더할 수 있는 경우
                    dp[i] += dp[prev];
                }
                dp[i] %= MOD;
            }
    
            return dp[len];
        }
    
        private static boolean isValidPermutation(char left, char right) {
            if(!isInAsciiRange(left, NUMBER_ASCII_START+1, NUMBER_ASCII_END)) {
                return false;
            }
    
            int num = (left - NUMBER_ASCII_START) * 10 + (right - NUMBER_ASCII_START);
            
            return isInAsciiRange(num, MIN, MAX);
        }
    
        private static boolean isInAsciiRange(char target, int min, int max) {
            return target >=min && target<=max;
        }
    
        private static boolean isInAsciiRange(int target, int min, int max) {
            return target >=min && target<=max;
        }
    
        private static boolean isValidInput(String inputStr) { // 0으로 시작하는 수인지, 0이 연속 2번 이상 들어가는지 확인
            return !inputStr.startsWith(WRONG_INPUT) &&
                    !Pattern.matches(CONTINUITY_ZERO, inputStr) &&
                    inputStr.length() >0 &&
                    isNumberString(inputStr);
        }
    
        private static boolean isNumberString(String inputStr) {
            String target = inputStr.replaceAll("[0-9]", "");
            return target.length() ==0;
        }
    }
    
    반응형

    '알고리즘 > 백준' 카테고리의 다른 글

    BOJ) 전깃줄 (2565 번)  (0) 2021.01.26
    BOJ) 달려라 홍준 (1306 번)  (0) 2021.01.26
    BOJ) GCD 합 (9613 번)  (0) 2021.01.26
    BOJ) 생물학자 (3116 번)  (0) 2021.01.21
    BOJ) 집합 (11723 번)  (0) 2021.01.21

    댓글

Designed by Tistory.