力扣第九十一题-解码方法

341 阅读2分钟

「这是我参与11月更文挑战的第14天,活动详情查看:2021最后一次更文挑战

前言

力扣第九十一题 解码方法 如下所示:

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

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

要 解码 已编码的消息,所有数字必须基于上述映射的方法,反向映射回字母(可能有多种方法)。例如,"11106" 可以映射为:

  • "AAJF" ,将消息分组为 (1 1 10 6)
  • "KJF" ,将消息分组为 (11 10 6)

注意,消息不能分组为  (1 11 06) ,因为 "06" 不能映射为 "F" ,这是由于 "6" 和 "06" 在映射中并不等价。

给你一个只含数字的 非空 字符串 s ,请计算并返回 解码 方法的 总数 。

题目数据保证答案肯定是一个 32 位 的整数。

示例 1:

输入: s = "12"
输出: 2
解释: 它可以解码为 "AB"1 2)或者 "L"12)。

示例 2:

输入: s = "226"
输出: 3
解释: 它可以解码为 "BZ" (2 26), "VF" (22 6), 或者 "BBF" (2 2 6) 。

一、思路

题目中有两个比较重要的信息:

  • 只需要保留最后解码 方法的 总数
  • 字符串中仅含有数字,可能会有前导 0
  • 类似于 06 是不可以被转换的

对于仅含有数字的字符,这省去了我们对于其他字符的判断。

我们发现一位数字 1 ~ 9 都是可以被转换的,两位数字的话需要判断是否在 10 ~ 26 这个区间。至于 0 的话就需要与它前面的那一个数字合在一起看区间是否在 10 ~ 26

我们发现 i (0 < i < s.len) 处编码的数量与 i-1 处编码的数量是有关系的。如下图所示:

image.png

假设我们直到 i-1 处的编码结果为 n,那么 m 处的编码结果呢?

很显然此时我们需要分情况讨论了,如下所示:

  • s[i] != 0s[i-1] + s[i] <= 26 :结果为 ret[i-1] + ret[i-2](还需要加上 i-2 处的结果)
  • s[i] != 0s[i-1] + s[i] > 26 时:结果为 ret[i-1]
  • s[i] == 0s[i-1] + s[i] <= 26 时:结果为 ret[i-2]
  • 其他情况,均为 0

根据上面的分析,我们很容易想到这一题可以使用动态规划来解决,大致的步骤如下所示:

因为使用的动态规划,所以存储结果的地方使用的一维数组 dp[]

  1. 遍历整个字符串
  2. 判断是否为 0,并根据规则填充 dp[i]
  3. 遍历结束,返回 dp[len-1] 的结果即可

二、实现

实现代码

实现代码与思路中保持一致,唯一值得注意的地方就是:需要考虑一些边界的情况。

s[i-1] + s[i] 是可以被解码时,但此时 i-2 < 0,即前面没有元素了,我们只需要加上 1 即可。(自身也算一种结果)

    public int numDecodings(String s) {
        // 特殊情况
        if (s.charAt(0) == '0')
            return 0;
        int len = s.length();
        int[] dp = new int[len];
        dp[0] = 1;  // 初始化
        for (int i = 1; i < len; ++i) {
            if (s.charAt(i) != '0') {
                dp[i] += dp[i - 1];
            }
            if (s.charAt(i - 1) != '0' && ((s.charAt(i - 1) - '0') * 10 + (s.charAt(i) - '0') <= 26)) {
                dp[i] += i > 1 ? dp[i - 2] : 1;   // 如果只有两个字符,则加上本身即可
            }
        }
        return dp[len-1];
    }

测试代码

    public static void main(String[] args) {
        new Number91().numDecodings("2102");
    }

结果

image.png

三、总结

感谢看到最后,非常荣幸能够帮助到你~♥

如果你觉得我写的还不错的话,不妨给我点个赞吧!如有疑问,也可评论区见~