1. 题目描述
2. 题目理解
最先想到的可能是递归,从第一个数字开始翻译,然后判断前两个数字能不能合并一起翻译,然后一直递归下去。用递归的话势必会存在重叠子问题,存在重叠子问题的话,可以用备忘录来进行剪枝。
递归从最大的问题开始自上而下解决问题,我们也可以从最小的子问题开始自下而上解决问题了,这样可以消除重复问题。
重叠子问题想到动态规划,是一个比较顺的思路了,我们从最小的子问题开始,就是从num的最后,对应的是dp[len-1]。
动态规划,状态数组定义:dp[i]表示从num[i]到结尾所有的数字所能翻译成的字符串的个数。
状态转移方程:dp[i]= dp[i+1](str[i]单独翻译的时候) + dp[i+2](str[i]和str[i+1]合在一起翻译的时候)
base case:
(1)i=str.length()-1的时候,dp[i]=1;
(2)i=str.length()-2的时候,dp[i]=dp[i+1]+1 (此时,dp[i+2]不存在)。
3. 代码
参考的《剑指offer》上的代码,dp数组换了个名字,成了counts数组,思路是一样的。
class Solution {
public:
int translateNum(int num) {
if(num<0)return 0;
string str=to_string(num);
return helper(str);
}
//动态规划,dp[i]表示:str[i~],从str[i]往后,所有的字符,组成的字符串的个数
//dp[i]= dp[i+1](str[i]单独翻译的时候) + dp[i+2](str[i]和str[i+1]合在一起翻译的时候)
//base case:
//i=str.length()-1的时候,dp[i]=1;
//i=str.length()-2的时候,dp[i]=dp[i+1]+1;(此时,dp[i+2]不存在)
int helper(const string& str){
int len=str.length();
int* counts=new int[len];
int count=0;
for(int i=len-1;i>=0;i--){
count=0;
if(i<len-1)count=counts[i+1];//以str[i]为单个字符,count+=counts[i+1]
else count=1;
if(i<len-1){
int digit1=str[i]-'0';
int digit2=str[i+1]-'0';
int converted=digit1*10+digit2;
if(converted>=10&&converted<=25){//以str[i]和str[i+1]两个组合为一个字符,count+=counts[i+2]
if(i<len-2)count+=counts[i+2];
else count+=1;
}
}
counts[i]=count;//动态规划,counts[i]=count;
}
count=counts[0];
delete[] counts;
return count;
}
};