1. 程式人生 > >動態規劃比遞迴快-LeetCode91-解碼方法

動態規劃比遞迴快-LeetCode91-解碼方法

題目


一條包含字母 A-Z 的訊息通過以下方式進行了編碼:

'A' -> 1
'B' -> 2
...
'Z' -> 26
給定一個只包含數字的非空字串,請計算解碼方法的總數。

示例 1:

輸入: "12"
輸出: 2
解釋: 它可以解碼為 "AB"(1 2)或者 "L"(12)。
示例 2:

輸入: "226"
輸出: 3
解釋: 它可以解碼為 "BZ" (2 26), "VF" (22 6), 或者 "BBF" (2 2 6) 。

思路1

遞迴。分為兩種情況:選前一個數解碼和選前兩個數解碼。然後將這兩種情況解碼數加起來。超時。

程式碼1

class Solution {
    public int numDecodings(String s) {
        if(s.charAt(0)=='0'){
            return 0;
        }
        if(s.length()==1){
            return 1;
        }

        // 1個
        int singlenum=0;
        singlenum=numDecodings(s.substring(1));

        
        // 2個
        int doublenum=0;
        if(Integer.parseInt(s.substring(0,2))>26){
            
        }else{
            if(s.length()==2){
                doublenum=1;
            }else{
                doublenum=numDecodings(s.substring(2));
            } 
        }
        
        return singlenum+doublenum;
    }
}

思路2

遍歷s。List<Integer>記錄目前所有解碼方式的最後數字。List.size即為所求。

如果當前字元不為'0' :遍歷List<Integer>拿到所有解碼方式的最後數字與當前字元結合為兩位數(或三位數),如果<=26則新增解碼方式。並將原解碼方式最後數字更新為當前字元。

如果當前字元為'0' :遍歷List<Integer>拿到所有解碼方式的最後數字與當前字元結合為兩位數(或三位數),如果<=26則新增解碼方式。並刪除錯誤的解碼方式(因為0不能單獨作為解碼)。

超時。

程式碼2

class Solution {
    public int numDecodings(String s) {

        if(s.charAt(0)=='0'){
            return 0;
        }
        
        
        List<Integer> l=new ArrayList<Integer>();
        l.add(s.charAt(0)-'0');
        
        for(int i=1;i<s.length();i++){
            if(s.charAt(i)!='0'){
                int lsize=l.size();
                for(int j=0;j<lsize;j++){
                    if( l.get(j)*10 + s.charAt(i)-'0'<= 26){
                        l.add(l.get(j)*10 + s.charAt(i)-'0');
                    }
                    l.set(j,s.charAt(i)-'0');
                }
            }else{
                int lsize=l.size();
                for(int j=0;j<lsize;j++){
                    if( l.get(j)*10 + s.charAt(i)-'0'<= 26){                    
                        l.add(l.get(j)*10 + s.charAt(i)-'0');
                    }
                    l.set(j,s.charAt(i)-'0');
                }
                for(int j=0;j<l.size();j++){
                    if(l.get(j)==0){
                        l.remove(j);
                        j--;
                    }
                }
            }
        }
        return l.size();
    }
}

思路3

動態規劃。int[] res記錄當前字串解碼數量。res[res.length-1]即為所求。

初始化res[0]=1。

尋找規律可以發現:

1.當前字元為 '0' : res[i]=res[i-2]

2.前一個字元為'0' : res[i]=res[i-1]

3.當前字元非0: 當前字元與前一個字元組合成兩位數。若<=26,則res[i]=res[i-1]+res[i-2];否則res[i]=res[i-1]。

程式碼3

class Solution {
    public int numDecodings(String s) {
        if(s.charAt(0)=='0'){
            return 0;
        }
        
        int[] res=new int[s.length()];
        res[0]=1;
        for(int i=1;i<s.length();i++){
            // 無法解碼的情況
            if(s.charAt(i)=='0' && s.charAt(i-1)=='0'){
                return 0;
            }
            if(s.charAt(i)=='0' && (s.charAt(i-1)-'0')*10+s.charAt(i)-'0' > 26){
                return 0;
            }
            
            // 0的情況
            if(s.charAt(i)=='0'){
                if(i-2>=0){
                    res[i]=res[i-2];
                }else{
                    res[i]=res[i-1];
                }
                continue;
            } 
            // 前一個是0的情況   
            if(s.charAt(i-1)=='0'){
                res[i]=res[i-1];
                continue;
            }
            // 非0情況
            if( (s.charAt(i-1)-'0')*10+s.charAt(i)-'0' <= 26){
                if(i-2>=0){
                    res[i]=res[i-1]+res[i-2];
                }else{
                    res[i]=res[i-1]*2;
                }
            }else{
                res[i]=res[i-1];
            }
        }
        return res[s.length()-1];
    }
}

總結

動態規劃比遞迴快。