091. Decode-Ways

difficulty: Medium

A message containing letters from A-Z is being encoded to numbers using the following mapping:

'A' -> 1
'B' -> 2
...
'Z' -> 26

Given a non-empty string containing only digits, determine the total number of ways to decode it.

Example 1:

Input: "12"
Output: 2
Explanation: It could be decoded as "AB" (1 2) or "L" (12).

Example 2:

Input: "226"
Output: 3
Explanation: It could be decoded as "BZ" (2 26), "VF" (22 6), or "BBF" (2 2 6).

Method One

class Solution {
    public int numDecodings(String s) {
        // 这个和之前的一样,主要是思想转不过来
        // 对于第 N 个字符,想要到达它,只能通过第 N - 1 和 第 N - 2 个字符。
        // 若通过 N - 1 到达 N ,解码方式只能把 N 单独解码。那么 dp[N] 加上 dp[N - 1];
        // 若通过 N - 2 到达 N ,解码方式只能把 N 和 N - 1 一起解码,那么 dp[N] 再加上 dp[N - 2];
        // 比如 987654321,到达1,可以通过 98765432,也可以通过 9876543 
        // 这个题还有0就比较恶心。因为如果有单独的 0,例如 909,那么总数直接是0.
        // 但是如果0可以和10 20 结合,那么 像 1020101 就可以有结合的方式,总数并不是0。

        //这个方法是最省空间的,但是处理edge cases 就很棘手。
        if(s.length() < 1) {
            return 0;
        }

        int prev2 = 1; // 第 1 个,作为辅助开始
        int prev  = s.charAt(0) == '0' ? 0:1; // 真实的第一个
        if(s.length() < 2) {
            return prev;
        }
        
        int cur = 0;
        for(int i = 1 ; i < s.length() ; i++ ) {
            int one = Integer.parseInt( s.substring(i, i + 1) );
            int two = Integer.parseInt( s.substring(i - 1, i + 1) );
            if( one == 0 ) {
                cur = 0;
            }
            if( one > 0 ) {
                cur = prev;
            }
            if( two > 9 && two < 27) {
                cur += prev2;
            }
            
            prev2 = prev;
            prev = cur;
        }
        return cur;        
    }
}

2022年写的,确实是好了很多啊。

class Solution {
    public int numDecodings(String s) {
        // substr(size - 1, size);
        // substr(size - 2, size);
        // int[] dp = new int[s.length + 1];
        int prevPrevWays = 0;
        int prevWays = 1;
        for(int i = 1; i <= s.length(); i++){
            int curWays = 0;
            if(isValid(s.substring(i - 1, i))){
                curWays += prevWays;
            }
            if(i > 1 && isValid(s.substring(i - 2, i))){
                curWays += prevPrevWays;
            }
            prevPrevWays = prevWays;
            prevWays = curWays;
        }
        return prevWays;
    }

    private boolean isValid(String s){
        int parsedInt = Integer.parseInt(s);
        if(parsedInt > 0 && parsedInt < 10 && !s.startsWith("0")){
            return true;
        }
        if(parsedInt >= 10 && parsedInt <= 26){
            return true;
        }
        return false;
    }
}

2023 年写的:

class Solution {
    public int numDecodings(String s) {
        int[] dp = new int[s.length() + 1];
        dp[0] = 1;
        for (int i = 0; i < s.length(); i++) {
            if (s.charAt(i) == '0') {
                dp[i + 1] = 0;
            } else {
                dp[i + 1] = dp[i];
            }
            if (i == 0) continue;
            int parsedInt = Integer.parseInt(s.substring(i - 1, i + 1));
            if (parsedInt <= 26 && parsedInt >= 10) {
                dp[i + 1] += dp[i - 1];
            }
        }
        return dp[s.length()];
    }
}

或者这样, 差不多。可以继续优化节省的那点空间意义不大。

class Solution {
    public int numDecodings(String s) {
        int[] dp = new int[s.length() + 1];
        dp[0] = 1;
        for (int i = 0; i < s.length(); i++) {
            if (s.charAt(i) != '0') {
                dp[i + 1] = dp[i];
            }
            if (i == 0) continue;
            int parsedInt = Integer.parseInt(s.substring(i - 1, i + 1));
            if (parsedInt <= 26 && parsedInt >= 10) {
                dp[i + 1] += dp[i - 1];
            }
        }
        return dp[s.length()];
    }
}

Last updated

Was this helpful?