【算法】Decode Ways II 解码方式2

【算法】Decode Ways II 解码方式2

题目

A message containing letters from A-Z is being encoded to numbers using the following mapping way:

‘A’ -> 1
‘B’ -> 2

‘Z’ -> 26
Beyond that, now the encoded string can also contain the character ‘*’, which can be treated as one of the numbers from 1 to 9.

Given the encoded message containing digits and the character ‘*’, return the total number of ways to decode it.

Also, since the answer may be very large, you should return the output mod 109 + 7.

Example 1:
Input: “"
Output: 9
Explanation: The encoded message can be decoded to the string: “A”, “B”, “C”, “D”, “E”, “F”, “G”, “H”, “I”.
Example 2:
Input: "1

Output: 9 + 9 = 18
Note:
The length of the input string will fit in range [1, 105].
The input string will only contain the character ‘*’ and digits ‘0’ - ‘9’.

编码方式如下:

  • 1 ~ 26 分别映射 “A” ~ “Z”
  • “*” 可以代指 0 ~ 9

给出一组长度为 [1,105] 的数字字符串,求可以有多少种解码方式。

解题思路

一个数字字符串,如果只考虑 0 ~ 9,没有 * ,则编码方式只有一种,在本题中由于将范围扩大到了 [1,26],且还有 * 插入,所以我们只需要针对字符串中的 1 、2、*进行针对处理即可。
以 6219 为例,62 和 621 分别有 1、2
假设当前字符串 sub[0,n-1] 、 sub[0,n] 有 i、j 种编码方式,若 sub[0,n] 的末尾字符为 1 ,则 sub[0,n+1] 计算时可分为两种情况(sub[0,n+1] 的末尾字符为 subn+1):

  1. subn+1 单独进行解码时,编码方式有 j 种
  2. subn+1 与 subn 进行合并解码时,编码方式有 i 种

所以 sub[0,n+1] = j + i = str[0,n] + str[0,n-1]。

在此基础上需要做一些区分的注意:

  1. 若subn+1 为 0 ,则只能与 subn 进行合并解码,不能单独解码。
  2. subn == 1,2 时,subn+1 在 [0,9],[0,6] 范围内,才能与 subn 进行合并解码。
  3. subn == * 时,由于 * 代指 [0,9],所以 subn+1 单独解码的方式 9 倍,合并解码时, 位数为 1 时解码方式 9 倍,尾数为 2 时解码方式 6 倍。

代码实现

Runtime: 100 ms
Memory: 20.5 MB

func numDecodings(_ s: String) -> Int {
        //字符串一共有多少种解码方式
        var e0:Int64 = 1
        //存储字符串末位为 1 时的编码方式数量
        var e1:Int64 = 0
        //存储字符串末位为 1 时的编码方式数量
        var e2:Int64 = 0
        //临时计算用的容器
        var f0:Int64 = 0
        //模的除数
        let M:Int64 = Int64(1e9 + 7)
        //遍历字符串 s
        for c in s
        {
            if c == "*"
            {
                //由于 * 可以代指 1 ~ 9
                //所以 e0 和 e1 都有九种方式,而最大到 26 所以 e2 只有 6 种
                f0 = 9 * e0 + 9 * e1 + 6 * e2
                //由于 * 可以代指 1 和 2,所以 e1 和 e2 都需要赋值
                e1 = e0
                e2 = e0
            }
            else
            {
                //先计算合并解码的情况
                //当前一位为 1 时,当前位在[0,9]范围内都可以进行合并解码,所以将 e1 加入到容器
                f0 = e1
                //当前一位为 2 时,当前位在[0,6]范围内才可以进行合并解码,将 e2 加入到容器
                if c <= "6"
                {
                    f0 += e2
                }
                
                //计算单独解码
                //如果当前字符为 0 ,则不能进行单独解码
                //所以只有当前位在[1,9]范围内才可以单独解码,将 e0 加入到容器
                if c > "0"
                {
                    f0 += e0
                }
                //依据当前字符是否为 1 或 2 ,来判断是将 e1 e2 为 e0 还是 0
                //以 61616 为例,当循环到 6161 时,当前字符为 1
                //在下次遍历到 6 时,由于会用到 616 和 6161 的结果
                //所以在此次遍历中,将 e0 赋值给 e1
                //这样,e1 中保留的就是 616 的结果,而 6161 的结果可在之后通过 f0 进行计算存储到 e0 中
                //当前字符不为 1 时,则下次遍历不会出现变动,故将 e1 变更为 0
                // e2 也是相同道理
                e1 = c == "1" ? e0 : 0
                e2 = c == "2" ? e0 : 0
            }
            //本次循环中,用 f0 % M 得出结果 e0
            e0 = f0 % M
        }
        //返回结果
        return Int(e0)
    }

代码地址:https://github.com/sinianshou/EGSwiftLearning

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值