题目:
这题我一开始想到的就是DFS遍历。因为之前有做过这种拆分问题。然后一看今天的每日一题(91.解码方法),好家伙,一摸一样。只不过那边的拆分需要进一步考虑‘0’的影响,但是本质上是一样的。
我们先来说说DFS的做法:
很简单,就是一直往下递归遍历就好了。只需要考虑每次是拆一个字符,还是拆两个字符,解空间类似一个二叉树。因为画图之后会发现有很多重复计算,所以用一个map数组去存储遍历到当前索引值的解个数。如果存在的话,说明已经计算过了,直接返回即可。
至于动态规划的做法,我觉得和DFS是一个反向的过程。DFS是一直拆解字符串,拆解到底层,然后逐一返回统计个数。动态规划更像是一开始就在计算,然后返回所有的个数。(当然,如果你要返回所有的解,还是要用DFS)
动态规划的思想是,对于每一个数字,都去考虑它是单独存在还是和前面结合存在。
如果可以单独存在的话,那么就等于去掉这个数字之后的所有解集。即dp【i】 = dp【i-1】
如果和前面结合起来存在的话,就相当于去掉这两个绑定数字之后的街机。即dp【i】 = dp【i-2】
那么,增加这个数字之后,总方案数就是这两种方案的和。
当然,这里需要判定是不是不满足题解条件,比如是否>25了。
C++(两种做法附带测试)
#include<iostream>
#include<vector>
#include<string>
#include<cstring>
#include<unordered_map>
using namespace std;
//class Solution {
//public:
// int translateNum(int num) {
// string s = to_string(num);
// int n = s.size();
// vector<int> dp(n+1,0);
// dp[0] = 1;
// dp[1] = 1;
// for(int i=2;i<n+1;i++){
// auto pre = s.substr(i - 2, 2);
// if(pre <= "25" && pre >= "10"){
// dp[i] = dp[i-1] + dp[i-2];
// }else{
// dp[i] = dp[i-1];
// }
// }
// return dp[n];
// }
//};
class Solution{
public:
int backtrace(string& str,int pos,vector<int> map){
int n = str.size();
if(pos>=n){
return 1;
}
if(map[pos]!=-1){
return map[pos];
}
if(pos==n-1||str[pos]=='0'||str.substr(pos,2)>"25"){
return backtrace(str,pos+1,map);
}
return backtrace(str,pos+1,map)+ backtrace(str,pos+2,map);
}
int translateNum(int num){
string str = to_string(num);
vector<int> map(str.size(),-1);
return backtrace(str,0,map);
}
};
int main(){
Solution solution;
cout<<solution.translateNum(12258);
}