DP学习第二篇之解码方法
一. 题目解析
二. 题解
算法原理及代码
- 状态表示
tips: 经验+题目要求。以i位置为结尾,。。。
dp[i]: 以i位置为结尾时,解码方法的总数
- 状态转移方程
tips: 用之前或之后的状态,推导出dp[i]的值。根据最近的一步,来划分问题
i下标位置为结尾时:
- s[i] 单独解码
- 成功, 1<= a <= 9,则解码方法数=dp[i-1]
- 失败,解码方法数=0
- s[i-1]和s[i] 一起解码
- 成功,10<= b*10 + a <= 26,则解码方法数=dp[i-2]
- 失败,0
即:dp[i] = dp[i-1] + dp[i-2],当成功时才加上对应的
- 初始化
tips: 保证填表的时候不越界。因此需要初始化0和1位置
dp[0]=1或0; //s[0]可否解码
dp[1] = 0或1或2; //s[1]可否解码、s[0]s[1]可否解码
- 填表顺序
从左往右(----->)
- 返回值
题目要求是整个字符串的解码方案数
即:return dp[n-1];
代码:
class Solution {
public:
int numDecodings(string s) {
//1.创建dp表
//2.初始化
//3.填表
//4.返回值
int n = s.size();
vector<int> dp(n);
if(s[0] != '0') dp[0] = 1;
if(n == 1) return dp[0];
if(s[1] != '0') dp[1] = dp[0];
int t = (s[0] - '0') * 10 + s[1] - '0';
if(t >= 10 && t <= 26) dp[1]++;
for(int i = 2; i < n; ++i)
{
if(s[i] != '0') dp[i] += dp[i - 1];
int t = (s[i - 1] - '0') * 10 + s[i] - '0';
if(t >= 10 && t <= 26) dp[i] += dp[i - 2];
}
return dp[n-1];
}
};
三.细节问题
小技巧 处理边界问题以及初始问题的技巧
对于上述题解中初始化
dp[1]
的操作比较繁琐。
在最前面增加一个虚拟节点,新dp[2] 需要 dp[0],dp[1]
注意事项:
- 虚拟节点里面的值,要保证后面填表是正确的
如果s[0]s[1]能够一起解码成功,则新dp[2] = + dp[0]
dp[0] = 1
,保证填2的时候是正确的
- 下标的映射关系
class Solution {
public:
int numDecodings(string s) {
//1.创建dp表
//2.初始化
//3.填表
//4.返回值
int n = s.size();
vector<int> dp(n+1);
//注意:下标的映射关系
dp[0] = 1;
if(s[0] != '0') dp[1] = 1;
for(int i = 2; i <= n; ++i)
{
if(s[i - 1] != '0') dp[i] = dp[i - 1];
int t = (s[i - 2] - '0') * 10 + s[i - 1] - '0';
if(t >= 10 && t <= 26) dp[i] += dp[i - 2];
}
return dp[n];
}
};
🦀🦀观看~~