剑指 Offer 46. 把数字翻译成字符串
title: 给定一个数字,我们按照如下规则把它翻译为字符串:0 翻译成 “a” ,1 翻译成 “b”,……,11 翻译成 “l”,……,25 翻译成 “z”。一个数字可能有多个翻译。请编程实现一个函数,用来计算一个数字有多少种不同的翻译方法。
输入: 12258
输出: 5
解释: 12258有5种不同的翻译,分别是"bccfi", "bwfi", "bczi", "mcfi"和"mzi"
一开始拿到题目,并没有太多的思路,只是觉得这是一个组合问题,一般组合问题,都可以用树形结构来表达。题目中存在某些隐形的条件:
- 被翻译的数字至多2位且不能超过25
- 被翻译的数字,不能有前导0
因为条件1的存在,就决定了每次翻译,只有2种选择:只翻译一个或者2个,那么可以尝试着去画一下组合树
用‘-’表示两个不同的部分,dash前是可以且已经被翻译,dash后是留着切分的,红色的点表示不能再往下切分了
拿到一个字符串后,有2种翻译方式组合:
- 只翻译一个数字
- 翻译2个数字
那么构建出来的树就是二叉树,我们每次翻译完本阶段后,接着切分并翻译剩下的字符串
红色的节点代表不能再被切分但可以被翻译,不能再切分是因为 - 前一步已经切分过,避免造成重复
- 已经满足了最小的翻译条件
那么这很明显属于DFS,递归好像不太好处理,就可以用栈来实现
class Solution {
public:
bool is_valid(string str){
if(str[0]=='0') //前导0不行
return false;
int str2int = atoi(str.c_str());
return str2int<=25;
}
int translateNum(int num) {
int count = 0;
string str_num = to_string(num);
int full_str_len = str_num.length();
stack<string> s;
s.push(str_num);
string tmp_str,first_str,sencond_str,rest_firstr_str,rest_second_str;
while(!s.empty()){
string top_str = s.top();
if(top_str.length()==1){
count++;
s.pop();
continue;
}
if(top_str.length()==2 && is_valid(top_str))
count++;//2位数且小于26,那么可以接受,也是一种情况
s.pop();
first_str = top_str.substr(0,1);
rest_firstr_str = top_str.substr(1,full_str_len);
//小于等于2位数的时候,就不用再继续切分了,因为上面已经切分
if(top_str.length()>2){
sencond_str = top_str.substr(0,2);
rest_second_str = top_str.substr(2,full_str_len);
if(is_valid(sencond_str))
s.push(rest_second_str);
}
s.push(rest_firstr_str);
}
return count;
}
};