剑指 Offer 46. 把数字翻译成字符串
方法:回溯、动态规划
解题思路
- 动态规划是回溯中“归”的过程;
- 思考回溯:
(1)将\(num\)转换为字符串\(s\);
(2)对于当前位置\(i\),可能有两种操作,将\(s[i] => 字符\) 或 将\(s[i, i + 1] => 字符\),即\(dfs(i) = dfs(i + 1) + dfs(i + 2)\)。
(3)\(dfs(i + 1)\)对应将\(s[i] => 字符\),\(dfs(i + 2)\)对应将\(s[i, i + 1] => 字符\)。 - 转换为动态规划
考虑回溯“归”的过程:对于\(当前dp值(dfs(i))\)由\(前一个dp值(dfs(i + 1))\)和\(前两个dp值(dfs(i + 2))\)决定,且\(i\)从\(n-1\)递减到\(0\)。
代码
回溯写法
class Solution {
public:
int translateNum(int num) {
string s = to_string(num);
int n = s.length();
vector<int> cache(n);
function<int(int)> dfs = [&](int i) -> int {
if (i == n) return 1; // 翻译为合法字符串
if (cache[i] != 0) return cache[i];
int res = dfs(i + 1);
if (s[i] != '0' && i + 1 < n) {
int idx = stoi(s.substr(i, 2));
if (idx < 26) res += dfs(i + 2);
}
cache[i] = res;
return res;
};
return dfs(0);
}
};
动态规划写法
class Solution {
public:
int translateNum(int num) {
string s = to_string(num);
int n = s.length(), last_1 = 1, last_2 = 1, dp = 1; // last_1表示前一个dp值,last_2表示前两个的dp值
for (int i = n - 1; i >= 0; i -- ) {
dp = last_1;
if (i + 1 < n && s[i] != '0' && stoi(s.substr(i, 2)) < 26) {
dp += last_2;
}
last_2 = last_1, last_1 = dp; // 更新变量
}
return dp;
}
};
复杂度分析
时间复杂度:回溯为\(O(n)\),\(dp\)为\(O(n)\);
空间复杂度:回溯为\(O(n)\),\(dp\)为\(O(1)\)。

浙公网安备 33010602011771号