leetcode_91.解码方法

一条包含字母 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) 。

解析:本题初看很像之前爬楼梯之类。
首先尝试使用递归方法解决问题。
定义函数R,返回对应字符串的解码结果数量
举例12026
从末尾开始看
对于6,很明显结果为1
对于26,结果为R(26)=R(6)+R()=2
对于026,结果为0
对于2026,结果为R(2026)=R(026)+R(26) =2
对于12026,结果为R(12026)=R(2026)+R(026)=2
可以得出结论,如果当前字符串前两个数字之和小于26,结果为R(p+1)+R(p+2)
否则为R(p+1),字符串不能以0开头

尝试写出代码

class Solution {
public:
    int numDecodings(string s) {
        if(s.size()==0) return 0;
        return recursive(s,0);
    }
    int recursive(string &s,int p){
        if(s.size()==p) return 1; //终止条件
        if(s[p]=='0') return 0; //没有0开头的数字
        int ans1 = recursive(s,p+1);
        int ans2 = (p<s.size()-1)?((((s[p]-'0')*10+(s[p+1]-'0'))<=26)?recursive(s,p+2):0):0;
        return ans1+ans2;
    }
};

问题已经解决,但是耗时极长,因为递归调用次数太多,相同的结果多次重复计算。

尝试减少重复计算次数。
将递归转化为迭代,定义一数组,长度与给定字符串相同,用来储存对应位置的解码结果数量,即上文中的函数R
从后往前遍历字符串,按位计算数量,最后数组的第一个元素即为答案

class Solution {
public:
    int numDecodings(string s) {
        if(s.size()==0) return 0;
        int l = s.size();
        int dp[l+1];
        memset(dp,0,sizeof(dp));
        dp[l]=1;
        if(s[l-1]=='0') dp[l-1]=0;
        else dp[l-1]=1;
        for(int i=l-2;i>=0;--i){
            if(s[i]=='0'){
                dp[i]=0;
                continue;
            }
            if(((s[i]-'0')*10+(s[i+1]-'0'))<=26){
                dp[i]=dp[i+1]+dp[i+2];
            }
            else{
                dp[i]=dp[i+1];
            }
        }
        return dp[0];
    }
};

将递归转换为迭代,时间利用率提升了无数倍。
观察整个过程。
对于某一个位置p,R§仅仅用到了R(p+1)与R(p+2),并且随着继续遍历,之前的R再也没有用到过。
因此可以将n个长度的数组转换为一个仅有三个元素的数组,分别储存R§、R(p+1)、R(p+2)
并且在每一次移动后,R§转换为新的R(p+1)、R(p+1)转换为新的R(p+2)
最后遍历完成后返回R§即可

class Solution {
public:
    int numDecodings(string s){
        if(s.size()==0||s[0]=='0') return 0;
        if(s.size()==1) return 1;
        int dp[3]{1,1,0};
        for(int i=2;i<s.size()+1;++i){
            if(s[i-1]=='0'){
                if(s[i-2]=='1'||s[i-2]=='2')
                    dp[2] = dp[0];
                else return 0;
            }
            else{
                if(s[i-2]=='1'||(s[i-2]=='2'&&s[i-1]<'7'))
                    dp[2] = dp[1]+dp[0];
                else
                    dp[2] = dp[1];
            }
            dp[0] = dp[1];
            dp[1] = dp[2];
        }
        return dp[2];
    }
};

时间复杂度O(n)
空间复杂度O(1)

发布了112 篇原创文章 · 获赞 0 · 访问量 360

猜你喜欢

转载自blog.csdn.net/qq_37292201/article/details/103903976