siriussilen
2019-11-12 09:04:47 +08:00
这道题,可以从记忆化递归的角度来理解,比如对于一个字符串 F("2213")=5, 可以分解为 F("213")和 F("13")两个子问题,在 F("213")这个子问题中又可以分为 F("13")和 F("3")两个子子问题,F("13")这个子子问题和 F("13")子问题是重复的,因而可以考虑使用记忆化搜索或动态规划来解决这个问题。
特别地,如果一个数中的一个前缀和两个前缀都是合法的,那么这个值等于斐波那契数列+1(此时解空间实际上就等价于斐波那契数列的状态转移方式),例如,f("12121212")=Fibonacci number(8+1) = 34
```cpp
class Solution {
public:
int numDecodings(string s) {
if(s.length() == 0) return 0;
unordered_map<string, int> ways;
ways[""] = 1;
function<int(const string &s)> dfs = [&](const string& s){
if(ways.count(s)) return ways[s];
if(s[0] == '0') return 0; // 第一位是 0,这是非法的返回 0
if(s.length() == 1) return 1; // e.g. 1-9,返回一种方式
int w = dfs(s.substr(1)); // 把第一位去掉,子问题 1
int prefix = stoi(s.substr(0,2)); // 取前两位,子问题 2
if(prefix <= 26) w += dfs(s.substr(2)); // 检查是否合法
ways[s] = w;
return w;
};
return dfs(s);
}
};
```
执行用时 :8 ms, 在所有 cpp 提交中击败了 37.55%的用户
内存消耗 :16.5 MB, 在所有 cpp 提交中击败了 5.18%的用户
记忆化搜索比较好理解,此外我的思考难免存在不足,欢迎批评指教