题目:
给定一个数字,我们按照如下规则把它翻译为字符串:0翻译成 ,1翻译成 ,……,11翻译成 (小写的 ),……,25翻译成 。一个数字可能有多个翻译。例如:12258有5种不同的翻译,分别是 、 、 、 和 。请编程实现一个函数,用来计算一个数字有多少种不同的翻译方法。
解题思路:
1.使用动态规划的思路来进行求解。
2.确定子问题:以12258为例子,求解12258有多少种翻译方法,可以分解为两个子问题,第一个子问题为’1’单独翻译和”2258”翻译,第二个为”12”联合翻译,”258”进行翻译。这样就等于求解”2258”和”258”一共有多少中翻译方法,以此类推。
3.确定转移方程:
代表从第i位数字开始不同翻译的数目,那么
4.尽量避免重复的子问题,选择使用自下而上、从小到达的方法来解决。把子问题的结果记录下来,用于计算下一次更大的问题。
//和《剑指offer》原解法略不同的方法
仍然使用动态规划的方法,剑指offer是从数字的末尾开始计算的,我们也可以从数字的开头开始计算。以12258为例子:
1.设f(i)为从高位开始的前i位数字可以翻译的方法数。f(0) = 1 且f(1) = 1
2.从i = 1开始,如果f(i)和f(i-1)组合起来可以一起翻译,那么f(i) = f(i-1)+f(i-2),否则f(i) = f(i-1)
#include <vector>
#include <string>
#include <stdlib.h>
#include <iostream>
#include <algorithm>
using namespace std;
//记录用的数组,初始化f(0) = 1,f(1) = 1
int cnt[70] = {1,1};
int getTranslationCnt(int num)
{
if(num < 0)return 0;
//转换成为string来处理
string numS = to_string(num);
int numSize = numS.size();
//从i=1,即从左到右第2个数字开始进行计算
for(int i = 1;i != numSize;i++){
//如果前一个数字是1,那么和当前数字总是能合并翻译
//所以f(i) = f(i-1)+f(i-2)
if(numS[i-1] == '1'){
cnt[i+1] = cnt[i] + cnt[i-1];
}
//如果前一个数字是2,那么只有当前数字是0~5才能合并翻译
else if(numS[i-1] == '2'){
if(numS[i] >= '0' && numS[i] <= '5'){
cnt[i+1] = cnt[i] + cnt[i-1];
}
else{
cnt[i+1] = cnt[i];
}
}
//前一个数字是其他数字,都不能合并翻译
else{
cnt[i+1] = cnt[i];
}
}
return cnt[numSize];
}
int main()
{
cout << "Please enter a posi integer:" << endl;
int test;
while(cin >> test){
cout << "The translation cnts are: " << getTranslationCnt(test) << endl;
//输入ctrl+d来退出,linux下的退出
cout << "Please enter a posi integer(ctrl+d to quit):" << endl;
}
return 0;
}