动态规划比递归快-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];
    }
}

总结

动态规划比递归快。

猜你喜欢

转载自blog.csdn.net/qq_36025975/article/details/83473865