这个题看了好几天,都没有思路,后来看到别人的题解,算是理解了一丢丢,现在整理下总体的思想。
题目
给定一个数字,我们按照如下规则把它翻译为字符串:0翻译成"a",1翻译成"b",…,25翻译成"z"。一个数字可能有多个翻译。例如,12258有5种不同的翻译,分别是"bccfi"、“bwfi”、“bczi”、“mcfi"和"mzi”。请编写实现一个函数,用来计算一个数字有多少种不同的翻译方法。
举个例子
1
的翻译个数是1
12
的翻译个数是2
- 1和2单独看作一个字母,即bc
- 1和2看成一个整体,翻译成一个字母,即m
122
的翻译个数3
- 1、2、2单独看作一个字母,即bcc
- 12 看作一个字母,2看作一个字母,即mc
- 1 看作一个字母,22看作一个字母,即bw
重点来了,那么1221
翻译的个数呢?共有以下两种情况!
情况一: 将12
前2位当作一个整体,然后在其翻译方法后面添加1个21
对应的字母,此时1221
与12
翻译的个数是一致的。
情况二: 将122
前3位当作一个整体,然后在其翻译方法后面添加1个1
对应的字母,此时1221
与122
翻译的个数是一致的。
也就是说,如果我们知道了前i-2位和前i-1位的翻译个数,就能得到前i位的翻译个数!
可以总结出如下的公式:
前i位可以翻译的个数 = 前i-1位可以翻译的个数+前i-2位可以翻译的个数
但是,这个公式还是存在一个bug,那就是如果第i为与第i-1位不能构成一个字母时,比如说1226
或者1209
,此时上述(1)过程就不能成立。所以,最终的公式内容为:
前 i 位 翻 译 的 个 数 = { 前 i − 1 位 可 以 翻 译 的 个 数 + 前 i − 2 位 可 以 翻 译 的 个 数 第 i 位 与 第 i − 1 位 构 成 数 字 小 于 26 且 大 于 9 前 i − 1 位 可 以 翻 译 的 个 数 第 i 位 与 第 i − 1 位 构 成 数 字 大 于 25 前i位翻译的个数={ \begin{cases} 前i-1位可以翻译的个数+前i-2位可以翻译的个数 &第i位与第i-1位构成数字小于26且大于9\\ 前i-1位可以翻译的个数 & 第i位与第i-1位构成数字大于25 \end{cases}} 前i位翻译的个数={前i−1位可以翻译的个数+前i−2位可以翻译的个数前i−1位可以翻译的个数第i位与第i−1位构成数字小于26且大于9第i位与第i−1位构成数字大于25
如果用dp[]数组保存前i位翻译的个数,那么公式如下:
d
p
[
i
]
=
{
d
p
[
i
−
1
]
+
d
p
[
i
−
2
]
第
i
位
与
第
i
−
1
位
构
成
数
字
小
于
26
且
大
于
9
d
p
[
i
−
1
]
第
i
位
与
第
i
−
1
位
构
成
数
字
大
于
25
dp[i]={ \begin{cases} dp[i-1] + dp[i-2] & 第i位与第i-1位构成数字小于26且大于9\\ dp[i-1] & 第i位与第i-1位构成数字大于25 \end{cases}}
dp[i]={dp[i−1]+dp[i−2]dp[i−1]第i位与第i−1位构成数字小于26且大于9第i位与第i−1位构成数字大于25
以122
为例子,检测一下这个公式,
d
p
[
3
]
=
d
p
[
2
]
+
d
p
[
1
]
=
2
+
1
=
3
dp[3] = dp[2] + dp[1] = 2 + 1 = 3
dp[3]=dp[2]+dp[1]=2+1=3
d
p
[
2
]
=
d
p
[
1
]
+
d
p
[
0
]
=
1
+
1
=
2
dp[2] = dp[1] + dp[0] = 1 + 1 = 2
dp[2]=dp[1]+dp[0]=1+1=2
注释,若符合每一位的翻译个数时,需要将dp[0]
和 dp[1]
初始化为1。同时,如果如果第i-1位与第i位构成的数字是09、08等,以0开头的,需要将其列为第二种情况!
有了以上的公式,那么代码就很简单了。
代码演示(Java)
public int translateNum2(int num) {
char[] numArrays = String.valueOf(num).toCharArray();
int length = numArrays.length;
int[] dp = new int[length + 1];
dp[0] = 1;
dp[1] = 1;
for (int i = 2; i <= length; i++) {
int a = (numArrays[i-2] - '0') * 10 + (numArrays[i-1] - '0');
//需要排除以0开头的两位数,如201
if (a > 9 && a < 26) {
dp[i] = dp[i-2] + dp[i-1];
} else {
dp[i] = dp[i-1];
}
}
return dp[length];
}
这道题用到了动态规划的思想!