返回

让编码逆风翻盘:解密LeetCode 91:解码方法的代码世界

闲谈

问题背景

LeetCode 91:解码方法题干:

给你一个只包含数字的字符串 s,其中每个数字可以映射到一个字母。例如,数字 '2' 可以映射到字母 'a'、'b' 或 'c'。

请你找出给定字符串有多少种不同的解码方法。

示例:

输入:s = "12"
输出:2
解释:它可以解码成 "ab"1 对应 "a"2 对应 "b")或者 "l"12 对应 "l")。
输入:s = "226"
输出:3
解释:它可以解码成 "aaa""aab""lc"

算法原理

为了求解 LeetCode 91 的问题,我们可以使用动态规划的思想。动态规划的核心在于将原问题分解为一系列子问题,然后依次解决这些子问题,最终得到原问题的解。

对于解码方法算法,我们可以将问题分解为以下子问题:

  1. 给定一个编码字符串 s,以 s[0] 开头的子字符串有多少种可能的解码方法?
  2. 给定一个编码字符串 s,以 s[1] 开头的子字符串有多少种可能的解码方法?
  3. ......
  4. 给定一个编码字符串 s,以 s[s.length() - 1] 开头的子字符串有多少种可能的解码方法?

通过依次解决这些子问题,我们可以得到整个字符串 s 的所有可能的解码方法。

实现步骤

  1. 初始化:

    创建长度为 s.length() + 1 的数组 dp,其中 dp[i] 表示以 s[i] 开头的子字符串有多少种可能的解码方法。将 dp[s.length()] 初始化为 1,因为空字符串只有一种可能的解码方法。

  2. 迭代:

    从 i = s.length() - 1 开始,依次递减至 i = 0。对于每个 i,计算以 s[i] 开头的子字符串有多少种可能的解码方法。具体步骤如下:

    • 如果 s[i] 是一个有效的数字(即 1-9),那么 dp[i] = dp[i+1],因为以 s[i] 开头的子字符串只有唯一的一种解码方法,即以 s[i] 对应的字母开头。
    • 如果 s[i] 和 s[i+1] 构成了一个有效的两位数(即 10-26),那么 dp[i] = dp[i+1] + dp[i+2],因为以 s[i] 开头的子字符串有两种可能的解码方法:一种是将 s[i] 和 s[i+1] 解码为一个字母,另一种是将 s[i] 单独解码为一个字母,然后将 s[i+1] 单独解码为一个字母。
  3. 返回结果:

    返回 dp[0],即以 s[0] 开头的子字符串有多少种可能的解码方法。

代码示例

public class Solution {
    public int numDecodings(String s) {
        int[] dp = new int[s.length() + 1];
        dp[s.length()] = 1;

        for (int i = s.length() - 1; i >= 0; i--) {
            if (s.charAt(i) != '0') {
                dp[i] = dp[i+1];
            }

            if (i + 1 < s.length() && (s.charAt(i) == '1' || (s.charAt(i) == '2' && s.charAt(i+1) <= '6'))) {
                dp[i] += dp[i+2];
            }
        }

        return dp[0];
    }
}

结语

LeetCode 91:解码方法是计算机编程中一个经典的动态规划算法问题,它要求我们计算给定编码字符串有多少种可能的解码方法。通过使用动态规划的思想,我们可以将原问题分解为一系列子问题,然后依次解决这些子问题,最终得到原问题的解。本文深入解析了 LeetCode 91 的问题背景、算法原理和实现步骤,帮助读者掌握这道编程难题的求解方法。