题目解析:数字翻译成字符串的可能性 | 豆包MarsCode AI刷题

71 阅读4分钟

问题描述

小M获得了一个任务,需要将数字翻译成字符串。翻译规则是:0对应"a",1对应"b",依此类推直到25对应"z"。一个数字可能有多种翻译方法。小M需要一个程序来计算一个数字有多少种不同的翻译方法。

例如:数字12258可以翻译成 "bccfi", "bwfi", "bczi", "mcfi" 和 "mzi",共5种方式。 样例1:

输入:num = 12258
输出:5

解题思路一:动态规划

  1. 定义状态:设dp[i]表示数字num的前i位有多少种不同的翻译方法。

  2. 状态转移方程:对于每一位数字num[j](其中j从1到nnnum的位数),我们有两种情况:

    • 如果num[j]不是0,那么它只能单独作为一个字符翻译,所以dp[j] = dp[j-1]
    • 如果num[j]是0,那么它可以与前一位数字组合起来作为一个字符翻译(如果前一位数字存在且在1到25之间),所以dp[j] = dp[j-1] + dp[j-2](假设num[j-1]是一个有效的字符)。
  3. 初始化dp[0] = 1(空字符串有一种翻译方法),dp[1] = 1(如果第一位数字有效,它有一种翻译方法)。

  4. 计算结果:遍历数字的每一位,根据状态转移方程更新dp数组,最后dp[n]就是数字num的总翻译方法数。

解题思路二:递归加记忆化

  1. 定义函数:定义一个函数f(i),表示从数字num的第i位开始有多少种不同的翻译方法。

  2. 递归情况

    • 如果i等于0,返回1,因为空字符串有一种翻译方法。
    • 如果num[i]是0,那么它可以与前一位数字组合起来翻译,所以f(i) = f(i-1) + f(i-2)(如果i > 1num[i-1]是一个有效的字符)。
    • 如果num[i]不是0,那么它只能单独作为一个字符翻译,所以f(i) = f(i-1)
  3. 记忆化:为了避免重复计算,我们可以使用一个数组或哈希表来存储已经计算过的f(i)的值。

  4. 计算结果:从f(n)开始,其中nnum的位数,递归地计算每个f(i)的值,直到f(1)f(0)

本题我选用动态规划解法详细如下:

  1. 定义状态dp[i]表示数字num的前i位有多少种不同的翻译方法。

  2. 初始化dp[0] = 1,表示空字符串有一种翻译方法。

  3. 遍历数字:从第一位数字开始遍历到第n位数字。

  4. 状态转移

    • 对于每一位数字,dp[i]的值至少等于dp[i-1],因为当前位可以独立作为一个字符。
    • 如果当前位和前一位可以组合成一个有效的字符(即两位数在10到25之间),则dp[i]还需要加上dp[i-2]的值,因为这两位可以组合成一个字符。
  5. 结果dp[n]即为整个数字num的翻译方法总数。

public static int solution(int num) {
    // 将整数转换为字符串
    String s = String.valueOf(num);
    // 获取字符串长度
    int n = s.length();
    // 初始化动态规划数组,长度为n+1,因为dp的索引从0开始
    int[] dp = new int[n + 1];
    // 初始化dp[0]为1,表示空字符串有一种翻译方法
    dp[0] = 1; 

    // 遍历字符串的每一位数字
    for (int i = 1; i <= n; i++) {
        // 当前位至少有一种翻译方法,即前一位的翻译方法数
        dp[i] = dp[i - 1]; 
        // 如果当前位不是第一位,可以检查是否可以与前一位组合
        if (i > 1) {
            // 提取当前位和前一位组成的两位数字符串
            String twoDigits = s.substring(i - 2, i); 
            // 检查两位数是否在10到25之间
            if (twoDigits.compareTo("10") >= 0 && twoDigits.compareTo("25") <= 0) {
                // 如果是,则当前位的翻译方法数还需要加上前两位的翻译方法数
                dp[i] += dp[i - 2]; 
            }
        }
    }

    // 返回整个数字的翻译方法总数
    return dp[n];
}