【DP】LeetCode 剑指 Offer 46. 把数字翻译成字符串

题目链接

剑指 Offer 46. 把数字翻译成字符串

思路

这个问题与 dp 中的经典问题“跳台阶”问题十分类似,在跳台阶问题中我们是选择跳一个台阶或者两个台阶,而在这个问题中我们是选择再统计一个字符还是再统计两个字符。即我们在遍历到第 \(i\) 个字符的时候,可以把它当做前面 \(i-1\) 个字符接上一个字符或者是前面 \(i-2\) 个字符接上两个字符。

举个栗子:

比如有一串数字为 12212
当我们遍历到 1221 时,我们可以看做两种情况:

  • 122 的后面接上了 1
  • 12 的后面接上了 21

所以1221的映射方法应该是122的映射方法数加上12的映射方法数,所以状态转移方程应该包含 \(dp[i]=dp[i-1]+dp[i-2]\)

这里我们把末尾两字符的值记为 \(value\)

只不过在跳台阶问题中我们无论怎样都能跳两个台阶,在该问题中需要满足 \(10 \leq value \leq 25\) 才能满足这两个字符能映射到字母,所以取 \(dp[i-2]\) 的值是有条件的。如果不满足条件,说明这种分割方法中的 \(value\) 没法映射到对应字母,即应该舍去 \(dp[i-2]\),此时状态方程变为 \(dp[i]=dp[i-1]\),即此时没法视为在 \(i-2\) 个字符的基础上接两个字符。

举个栗子:

比如有一串数字为 12345
当我们遍历到 1234 时,我们可以看做两种情况:

  • 123 的后面接上了 4
  • 12 的后面接上了 34

但是 34 已经超过了 25,所以它没有映射的字母,需要把这种情况舍去。

综上所述,状态转移方程应该为:

\[dp[i]=\left\{ \begin{aligned} & dp[i-1], & value <10, \\ & dp[i-1] + dp[i-2],& 10 \leq value \leq 25. \\ \end{aligned} \right. \]

代码

dp数组版

class Solution {
    public int translateNum(int num) {
        // dp[i] = dp[i - 1] + dp[i - 2]
        String string = String.valueOf(num);
        if(string.length() == 1){
            return 1;
        }

        int[] dp = new int[string.length()];

        dp[0] = 1;
        dp[1] = Integer.valueOf(string.substring(0, 2)) > 25 ? 1 : 2;
        for(int i = 2; i < string.length(); i++){
            String subString = string.substring(i - 1, i + 1);
            int value = Integer.valueOf(subString);
            if(10 <= value && value <= 25){
                dp[i] = dp[i - 1] + dp[i - 2];
            }else{
                dp[i] = dp[i - 1];
            }
        }
		
        return dp[string.length() - 1];
    }
}

空间优化版

class Solution {
    public int translateNum(int num) {
        // dp[i] = dp[i - 1] + dp[i - 2]
        String string = String.valueOf(num);
        if(string.length() == 1){
            return 1;
        }

        int pre = 1;
        int pre2 = Integer.valueOf(string.substring(0, 2)) > 25 ? 1 : 2;
        int next = pre2;
        for(int i = 2; i < string.length(); i++){
            String subString = string.substring(i - 1, i + 1);
            int value = Integer.valueOf(subString);
            if(10 <= value && value <= 25){
                next = pre + pre2;
            }else{
                next = pre2;
            }
            pre = pre2;
            pre2 = next;
        }

        return next;
    }
}
posted @ 2023-03-27 10:32  Frodo1124  阅读(20)  评论(0编辑  收藏  举报