알고리즘/LeetCode

[LeetCode] 91. Decode Ways - 동적계획법(Dynamic Programming) JAVA

passionfruit200 2025. 2. 9. 13:56

https://leetcode.com/problems/decode-ways/description/

코드설명

동적계획법(Dynamic Programming) 을 활용합니다.

 

1글자로 짜르는 경우, 2글자로 짜르는 경우를 모두 완전탐색으로 탐색한뒤, 해당 구조가 최적 부분구조를 만족하므로 동적계획법을 활용해 중복연산을 피합니다.

 

leading zeros가 존재하는 문자인지, 1~26까지의 숫자로 가능한 알파벳인지의 여부를 확인하는 로직도 신경써서 구현합니다. 

 

이 문제의 경우, 저의 경우 leading zeros를 상당히 비효율적으로 구현하였습니다. 사실, 맨 앞에 '0'이 존재한다는 의미는, 무엇을 하든간에 0이 존재하므로 잘못된 경우입니다. 그렇기에 사실상 맨앞만 처리하면 되는 것이지요.

if(Str.length() >= 1 && str.charAt(0) == '0') return false;

코드

개선시킨 정답코드 2입니다.

isLeadingZero 판별로직이 훨씬 간단해졌습니다.

class Solution {
    int[] cache = new int[101];
    public int numDecodings(String s) {
        Arrays.fill(cache, -1);
        return DFS(0, s);
    }

    int DFS(int startIdx, String s){
        if(startIdx == s.length()){
            return 1;
        }
        if(cache[startIdx] != -1) return cache[startIdx];
        int ret = 0;
        //1글자로 짜르는 경우
        int endIdx = startIdx + 1;
        String str = s.substring(startIdx, endIdx);
        //해당 str이 leading zero 라면, 작동안됩니다.
        if( isNonLeadingZeroAndIsAlphabet(str) == true){
            ret += DFS(endIdx, s);
        }

        //2글자로 짜르는 경우
        endIdx = startIdx + 2;
        str = null;
        if(endIdx <= s.length())
            str = s.substring(startIdx, endIdx);
        if(str != null && isNonLeadingZeroAndIsAlphabet(str) == true){
            ret += DFS(endIdx, s);
        }
        return cache[startIdx] = ret;
    }

    boolean isNonLeadingZeroAndIsAlphabet(String str){
        if(str.length() >= 1 && str.charAt(0) == '0') return false;

        int idx = 0;
        int sum = 0;
        while(idx < str.length()){
            int num = str.charAt(idx) - '0';
            sum = sum * 10 + num;
            idx++;
        }
        if(sum < 0 || sum > 26) return false;
        return true;
    }

}

 

정답코드1입니다.

이 코드의 경우 isLeadingZero를 상당히 비효율적으로 작성했습니다.

class Solution {
    int[] cache = new int[101];
    public int numDecodings(String s) {
        Arrays.fill(cache, -1);
        return DFS(0, s);
    }

    int DFS(int startIdx, String s){
        if(startIdx == s.length()){
            return 1;
        }
        if(cache[startIdx] != -1) return cache[startIdx];
        int ret = 0;
        //1글자로 짜르는 경우
        int endIdx = startIdx + 1;
        String str = s.substring(startIdx, endIdx);
        //해당 str이 leading zero 라면, 작동안됩니다.
        if( isNonLeadingZeroAndIsAlphabet(str) == true){
            ret += DFS(endIdx, s);
        }

        //2글자로 짜르는 경우
        endIdx = startIdx + 2;
        str = null;
        if(endIdx <= s.length())
            str = s.substring(startIdx, endIdx);
        if(str != null && isNonLeadingZeroAndIsAlphabet(str) == true){
            ret += DFS(endIdx, s);
        }
        return cache[startIdx] = ret;
    }

    boolean isNonLeadingZeroAndIsAlphabet(String str){
        int idx = 0;
        boolean isLeadingZeroFound = false;
        int sum = 0;
        while(idx < str.length()){
            //만약 첫 숫자라면, 성공임.
            int num = str.charAt(idx) - '0';
            sum = sum * 10 + num;

            if(idx == 1)
                isLeadingZeroFound = true;
            if(isLeadingZeroFound == false && num == 0){
                return false;
            }
            idx++;
        }
        if(sum < 0 || sum > 26) return false;
        return true;
    }

}