- 操作系统:ubuntu22.04
- IDE:Visual Studio Code
- 编程语言:C++11
题目描述
给定一个数字,它要么作为一个数字单独翻译成一个字符(‘a’ ~ ‘z’),要么和后面一位组合,翻译成另一个字符。
规则如下:
数字 0 → 'a'
数字 1 → 'b'
...
数字 25 → 'z'
例如:
12258 可以翻译为 "bccfi"、"wafi"、"bczi"、"wcfi" 等。
请输出这个数字能翻译成多少种不同的字符串?
示例:
输入: 12258
输出: 5
解释:
12258 → "bccfi"
12258 → "wafi"
12258 → "bczi"
12258 → "wcfi"
12258 → "wbfi"
解法思路:动态规划(DP)
这是一道典型的动态规划问题,与“爬楼梯”、“斐波那契数列”类似,具有重叠子结构和最优子结构特性。
定义状态:
设 dp[i] 表示从数字的第 i 位开始到末尾可以翻译成的不同字符串数量。
状态转移方程:
- 单个数字可以翻译:dp[i] = dp[i+1]
- 如果当前两位组成的数字在 [10, 25] 范围内,则也可以一起翻译:dp[i] += dp[i+2]
边界条件:
- dp[n] = 1(空字符串有一种翻译方式)
- dp[n-1] = 1(最后一个数字只有一种翻译方式)
实现代码
#include <string>
#include <vector>
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[ n ] = 1;
dp[ n - 1 ] = 1;
for ( int i = n - 2; i >= 0; --i )
{
// 单独翻译当前位
dp[ i ] = dp[ i + 1 ];
// 判断是否可以两个数字一起翻译
int twoDigit = stoi( s.substr( i, 2 ) );
if ( twoDigit >= 10 && twoDigit <= 25 )
{
dp[ i ] += dp[ i + 2 ];
}
}
return dp[ 0 ];
}
};
#include <iostream>
int main() {
Solution sol;
cout << sol.translateNum(12258) << endl; // 输出 5
cout << sol.translateNum(0) << endl; // 输出 1
cout << sol.translateNum(5) << endl; // 输出 1
cout << sol.translateNum(25) << endl; // 输出 2
return 0;
}