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

作者: 无良剑染 | 来源:发表于2020-02-22 17:56 被阅读0次

    题目

    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

    相关文章

      网友评论

        本文标题:【算法】Decode Ways II 解码方式2

        本文链接:https://www.haomeiwen.com/subject/vbtrqhtx.html