(Java) LeetCode 91. Decode Ways —— 解碼方法


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).

 

這個題想了好久,覺得真的是比較難想,好多case一遍一遍測試才通過。試着總結一下思路吧。

首先,假如我們分析到了中間,比較通用的情況。

現在在已有字符串的基礎上,新來一位字符,就要開始分情況。如果來的是'0',就只有唯一的組成情況,就是和前面的一個數字組成編碼,且前面的這個數字還必須是'1'或'2',否則就是無效的編碼。所以如果來的是'0',相當於要么和前面的數字組合,要么就無效。如果用動態規划的思想,那就先寫上偽代碼:

if (s[i] == '0') { 
    if (s[i-1] == '1' || '2') 
        dp[i] = dp[i-2]; 
    else 
        return 0;
}     

這里為什么是dp[i] = dp[i-2]呢?因為'0'只能作為和前面的一位字符組合存在,所以前面的字符出現的時候相當於並沒有出現,因為它要等着后面的'0'來和它組合,所以編碼種類和dp[i-2]一樣多。

接下來看如果來的是'1'~'9',不僅自己要再細分情況,也要再考慮前面一位的情況。如果前面一位是'1',或前一位是'2'且這一位是'1'~'6',那么可以產生新的編碼,因為它既可以獨立存在成一個字母,又可以和前面的數字組合形成一個字母。作為獨立存在的情況相當於就是取dp[i-1],因為添加一位獨立存在的字符並沒有增加任何可能性,所以保持和前狀態一樣;作為組合存在的情況同上,還要再往前想一位。因為如果組合存在的話,前面的一位其實也是和后面的一位作為組合存在而不是獨立存在,即當dp[i-1]那位字符來的時候,裝作它沒來,因為它要等着和后面的字符結合,所以編碼種類和dp[i-2]是一樣多的。所以最后dp[i] = dp[i-1] + dp[i-2]。

如果前面一位字符不是'1'或者'2',那么新來的字符位只能作為獨立存在,無法結合。所以並沒有產生新的編碼可能,即dp[i] = dp[i-1]。

總結起來偽代碼如下:

if (s[i-1] == '1' || (s[i-1] == '2' && '1' <= s[i] <= '6')) 
  dp[i] = dp[i-1] + dp[i-2];
else
  dp[i] = dp[i-1];

這樣所有的情況就分析完了。現在看為了解決通用情況需要些什么,很明顯從上面來看,需要知道每一位字符前兩位,即dp[0]和dp[1]要首先知道。dp[0]很簡單,如果不是'0'那就是1,是'0'就直接返回0了,第一位是'0'無法解碼。dp[1]也並不復雜,其實和通用情況一樣,如果第二位是'0',dp[1]就是1或return 0,取決於能否和前面結合,即第一位是否是'1'或'2';如果第一位是'1',或第一位是'2'且第二位是'1'~'6',那dp[1]就是2,因為可以結合或獨立存在。其他情況就都是1了,因為只能獨立存在,不增加解碼可能性。

寫完了思路發現這道題就寫完了,把思路實現即為代碼。應該是有很多可以優化的地方,或者是思緒上,或者是代碼上,留作以后復習的時候優化吧。現在這么寫思路特別清楚,很容易理解,姑且先這樣吧!

 


Java

class Solution {
    public int numDecodings(String s) {
        if (s == "") return 0;
        char[] digit = s.toCharArray();
        int[] dp = new int[digit.length];
        //get dp[0]
        dp[0] = digit[0] == '0' ? 0 : 1;
        if (dp[0] == 0 || digit.length == 1) return dp[0];
        //get dp[1]
        dp[1] = 1;
        if (digit[1] == '0') {
            if (digit[0] >= '3')
                return 0;
        }
        else if (digit[0] == '1' || (digit[0] == '2' && '1' <= digit[1] && digit[1] <= '6'))
                dp[1] = 2;
        //get dp[i]
        for (int i = 2; i < digit.length; i++) {
            if (digit[i] == '0') {
                if (digit[i-1] == '1' || digit[i-1] == '2')
                    dp[i] = dp[i-2];
                else return 0;
            }
            else if (digit[i-1] == '1' || (digit[i-1] == '2' && '1' <= digit[i] && digit[i] <= '6')) 
                dp[i] = dp[i-1] + dp[i-2];
            else dp[i] = dp[i-1];
        }
        return dp[digit.length-1];
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM