题目要求:
给定一个数字,按照如下规则翻译成字符串:0翻译成“a”,1翻译成“b”…25翻译成“z”。一个数字有多种翻译可能,例如12258一共有5种,分别是bccfi,bwfi,bczi,mcfi,mzi。实现一个函数,用来计算一个数字有多少种不同的翻译方法。
参考至该作者
自上而下,从最大的问题开始,递归 :
12258
/ \
b+2258 m+258
/ \ / \
bc+258 bw+58 mc+58 mz+8
/ \ \ \ \
bcc+58 bcz+8 bwf+8 mcf+8 mzi
/ \ \ \
bccf+8 bczi bwfi mcfi
/
bccfi
有很多子问题被多次计算,比如258被翻译成几种这个子问题就被计算了两次。
自下而上,动态规划,从最小的问题开始 :
f(r)表示以r为开始(r最小取0)到最右端所组成的数字能够翻译成字符串的种数。对于长度为n的数字,f(n)=0,f(n-1)=1,求f(0)。
递推公式为 f(r-2) = f(r-1)+g(r-2,r-1)*f(r);
其中,如果r-2,r-1能够翻译成字符,则g(r-2,r-1)=1,否则为0。
因此,对于12258:
f(5) = 0
f(4) = 1
f(3) = f(4)+0 = 1
f(2) = f(3)+f(4) = 2
f(1) = f(2)+f(3) = 3
f(0) = f(1)+f(2) = 5
上代码:
public class TranslateNumbersToStrings {
public static int getTranslationCount(int number){
if(number<0)
return 0;
if(number==1)
return 1;
return getTranslationCount(String.valueOf(number));
}
//动态规划,从右往左算
// f(i) = f(i+1)+f(i+2)*g(i,i+1),其中g(i,i+1)用来判断两位是否满足0~25
private static int getTranslationCount(String str) {
int f1 = 0;
int f2 = 1;
//判断两位数是否是0=<g<=25
int g = 0;
/*
* f(5) = f1 = 0;
* f(4) = f2 = 1;
* f(3) = f(4) + f(5)*g(3,4)
* f(2) = f(3) + f(4)
* */
for(int i = str.length()-2;i >= 0;i--)
{
g = (str.charAt(i)-'0')*10 + (str.charAt(i+1)-'0');
if((0<=g)&&(g<=25))
{
int temp = f2;
f2 = f1 + f2;
f1 = temp;
}
else{
f1 = f2;
}
}
return f2;
}
public static void main(String[] args) {
System.out.println(getTranslationCount(12258));
System.out.println(getTranslationCount(50008));
}
}
此外,在剑指Offer上面的解析中对g(i,i+1)的解释是10<=g<=25,我觉得不正确,比如101中的01不止代表一种,我觉得可以分开为0,1和01这两种情况分别对应ab和b,因为题目中的要求0是有代表字母a的。不知道有没大佬能给我解释一下。