这是是题目描述:剑指Offer-面试题46:把数字翻译成字符串
方法一:递归
定义函数f(i)
表示以从左向右第i
位开始的不同翻译数目,有f(i)=f(i+1)+f(i+2)*g(i,i+1)
,表示分别以第i
位的一位数字和第i:i+1
的两位数字为前缀的翻译数目的和就是我们要求的和,g(i,i+1)
表示第i:i+1
的两位数字是否在10~25的范围内,若是,g(i,i+1)=1
,否则g(i,i+1)=0
,递归求f(i+1)
和f(i+2)
题解代码:
class Solution {
public int translateNum(int num) {
String str=num+"";
return translateStr(str);
}
int translateStr(String str)
{
if(str.length()<=1)
{
return 1;
}
int sum=0; //统计当前str能被翻译成的字符串的个数
for(int i=0;i<str.length();i++)
{
String preFix=str.substring(0,i+1);
int preNum=Integer.parseInt(preFix);
if(preNum>25 || (preFix.length()>1 && preFix.charAt(0)=='0'))
{
break;
}
sum+=translateStr(str.substring(i+1));
}
return sum;
}
}
方法二:从最小子问题开始分析,消除重叠子问题
递归法是从最大的问题开始,自上而下解决问题,但存在重复的子问题: 以数字12258
为例可分解为两个子问题:翻译1
和2258
,以及翻译12
和258
。而翻译2258
同样可分解为翻译2
和258
以及翻译22
和58
。这里子问题翻译258
重复了
因此,我们可以从最小的子问题开始自下而上的解决:以12258
为例,先翻译最右边的8
和58
并记录下来;再翻译258
,可分解为已经记录的子问题8
和 58
,将它们相加就是258
的结果;依次类推得到2258
、12258
的结果,且没有重复计算子问题
题解代码:
class Solution {
public int translateNum(int num) {
String str=num+"";
return translateStr(str);
}
int translateStr(String str)
{
int[] count=new int[str.length()+1]; //count[i]存储str[i:str.lrngth]所对应的数字能翻译成的字母字符串个数
count[count.length-1]=1; //多加的最后一位方便计算
count[count.length-2]=1;
for(int i=count.length-3;i>=0;i--)
{
count[i]+=count[i+1];
if(Integer.parseInt(str.substring(i,i+2))<=25 && str.charAt(i)!='0')
{
count[i]+=count[i+2];
}
}
//System.out.println(Arrays.toString(count));
return count[0];
}
}