1. 解密数字
现有一串神秘的密文 ciphertext,经调查,密文的特点和规则如下:
密文由非负整数组成
数字 0-25 分别对应字母 a-z
请根据上述规则将密文 ciphertext 解密为字母,并返回共有多少种解密结果。
示例 1:
输入: ciphertext = 216612
输出: 6
解释: 216612 解密后有 6 种不同的形式,分别是 "cbggbc","vggbc","vggm","cbggm","cqgbc" 和 "cqgm"
提示:
0 <= ciphertext < 231
这个问题可以通过动态规划来解决。我们需要找出一种方法,将一个给定的数字 ciphertext
转化为对应的翻译方式,具体翻译规则是:
- 每个数字(1-9)可以被单独翻译。
- 由两个数字组成的两位数(10-25)也可以翻译为一个字符。
动态规划解题思路
-
定义状态:
设dp[i]
表示到数字的第i
位时,所有可能的翻译方法数。我们需要计算dp[n]
,其中n
是ciphertext
的位数。 -
转移方程:
-
对于每一位数字
dp[i]=dp[i−1]+dp[i−2]dp[i] = dp[i-1] + dp[i-2]x[i]
,如果它与前一位数字x[i-1]
组成的两位数在 [10, 25] 范围内,则可以将这两位数作为一个字符翻译。因此,状态转移公式为:其中:
dp[i-1]
表示当前位数字单独翻译的情况。dp[i-2]
表示当前位数字与前一位数字组成的两位数翻译的情况(如果符合条件)。
-
如果
dp[i]=dp[i−1]dp[i] = dp[i-1]x[i-1]
和x[i]
组成的两位数不在 [10, 25] 范围内,则:
-
-
初始化:
dp[0] = 1
,表示“无数字”的翻译方法数。dp[1] = 1
,表示仅有一个数字时的翻译方法数。
-
最后的结果:
结果是dp[n]
,即数字ciphertext
的翻译方案数。
代码实现
方法一:字符串遍历
class Solution {
public int crackNumber(int ciphertext) {
String s = String.valueOf(ciphertext); // 将数字转换为字符串
int a = 1, b = 1; // 初始状态 dp[0] = 1, dp[1] = 1
for(int i = 2; i <= s.length(); i++) {
String tmp = s.substring(i - 2, i); // 获取当前位和前一位的两位数
int c = (tmp.compareTo("10") >= 0 && tmp.compareTo("25") <= 0) ? a + b : a; // 判断是否在可翻译的范围内
b = a; // 更新 dp[i-1]
a = c; // 更新 dp[i]
}
return a; // 返回 dp[n]
}
}
方法二:数字求余
为了节省空间,我们可以直接利用数字的除法和取余操作来获取每一位数字。这个方法通过从右到左进行动态规划,避免了字符串的使用。
class Solution {
public int crackNumber(int ciphertext) {
int a = 1, b = 1, x, y = ciphertext % 10; // 获取个位数字
while