Leetcode 639. 解码方法 2 C++

Leetcode 639. 解码方法 2

题目

一条包含字母 A-Z 的消息通过以下的方式进行了编码:

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

除了上述的条件以外,现在加密字符串可以包含字符 ’ * ‘了,字符’ * '可以被当做1到9当中的任意一个数字。

给定一条包含数字和字符’*'的加密信息,请确定解码方法的总数。

同时,由于结果值可能会相当的大,所以你应当对109 + 7取模。(翻译者标注:此处取模主要是为了防止溢出)

测试样例

示例 1 :

输入: "*"
输出: 9
解释: 加密的信息可以被解密为: "A", "B", "C", "D", "E", "F", "G", "H", "I".

示例 2 :

输入: "1*"
输出: 9 + 9 = 18(翻译者标注:这里1*可以分解为1,* 或者当做1*来处理,所以结果是9+9=18)

说明 :

  • 输入的字符串长度范围是 [1, 105]。
  • 输入的字符串只会包含字符 ‘*’ 和 数字’0’ - ‘9’。

题解

动态规划
令dp[i]表示从0~i解密方式
则转移方程为

  • 当s[i]!=*
    • dp[i] = dp[i-1]+1+(if 如果s[i-1]s[i]<=26 +dp[i-2]+1 then +0)
  • s[i]==*
    • dp[i] = dp[i-1]+9 + (if s[i-1]==1 +dp[i-2]+1 else if s[i-1]==2 +dp[i-2]+7 else +0)
      初始条件,我们需要考虑dp[0]、dp[1]
      详细过程见代码

代码

	int numDecodings(string s) {
        if(s.empty())   return 0;
        int mod = pow(10,9)+7,len=s.length();
        if(len == 1){		//只有1位时
            if(s[0] == '0') return 0;		//没有此情况
            if(s[0] == '*') return 9;		//可以将*解码为1~9,9种情况
            return 1;
        }
        vector<long> dp(len,0);
        if(s[0]=='0')   return 0;
        if(s[0]=='*')   dp[0]=9;
        else dp[0]=1;
        if(s[1]=='*'){			//考虑前两位
            dp[1] = dp[0]*9;	//两位单独解密
            if(s[0]=='1') dp[1] += 9;       //11~19
            else if(s[0]=='2')    dp[1] += 6;   //21~26,6种情况
            else if(s[0]=='*')    dp[1] += 15;  //11~19+21~26,15种情况
        }else if(s[1]=='0'){		//只有10、20两种情况
            if(s[0]=='0' || s[0]<='9' && s[0]>'2')  return 0;   
            if(s[0]=='*')   dp[1] = 2;      //10+20 两种情况
            else dp[1] = 1;			//10或20
        }else{
            dp[1] = dp[0];		//两位单独解密
            if(s[0]=='1')   dp[1]++;		//出现2位共同解码,即11~19中的1种情况
            else if(s[0]=='2' && s[1]<'7')  dp[1]++;		//出现2位共同解码,即21~26中的1种情况
            else if(s[0]=='*' && s[1]<'7')  dp[1]+=2;		//11~16中的1种情况及21~26中的1种情况,共2种情况
            else if(s[0]=='*' && s[1]>'6')  dp[1]++;   		//17~19中的1种情况
        }
        for(int i=2; i<len; i++){
            if(s[i]=='*'){
                dp[i] = (dp[i-1]*9)%mod;		//s[i]可以单独解密
                if(s[i-1]!='0'){
                    if(s[i-1]=='*') dp[i] = (dp[i]+dp[i-2]*15)%mod;		//s[i-1]和s[i]作为一个整体进行解密,且可以解密为11~19+21~26,15种情况
                    else if(s[i-1]=='1')    dp[i] = (dp[i]+dp[i-2]*9)%mod;	//s[i-1]和s[i]作为一个整体进行解密,且可以解密为11~19,9种情况
                    else if(s[i-1]=='2')    dp[i] = (dp[i]+dp[i-2]*6)%mod;	//s[i-1]和s[i]作为一个整体进行解密,且可以解密为21~26,6种情况
                } 
            }else if(s[i]=='0'){		//只能是10或20
                if(s[i-1]=='0' || s[i-1]<='9' && s[i-1]>'2')  return 0;		
                if(s[i-1]=='*') dp[i] = (dp[i-2]*2)%mod;		//s[i-1]和s[i]作为一个整体进行解密,解密为10和20,2种情况
                else    dp[i] = dp[i-2];		//s[i-1]和s[i]作为一个整体进行解密,解密为10或20,1种情况
            }else{
                dp[i] = dp[i-1];		//s[i]可以单独解密
                if(s[i-1]=='1') dp[i] = (dp[i]+dp[i-2])%mod;	//s[i-1]和s[i]作为一个整体进行解密,且可以解密为11~19+21~26中的1种情况
                else if(s[i-1]=='2' && s[i]<'7')    dp[i] = (dp[i]+dp[i-2])%mod; 	//s[i-1]和s[i]作为一个整体进行解密,且可以解密为11~16+21~26中的1种情况
                else if(s[i-1]=='*' && s[i]<'7')  dp[i] = (dp[i]+dp[i-2]*2)%mod;	//s[i-1]和s[i]作为一个整体进行解密,且可以解密为11~16中的1种情况和21~26中的1种情况,共2种情况
                else if(s[i-1]=='*' && s[i]>'6')  dp[i] = (dp[i]+dp[i-2])%mod;	//s[i-1]和s[i]作为一个整体进行解密,且可以解密为17~19中的1种情况
            }
        }
        return dp[len-1];
    }

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/decode-ways-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值