题目描述:
A message containing letters from A-Z
is being encoded to numbers using the following mapping:
'A' -> 1 'B' -> 2 ... 'Z' -> 26
Given an encoded message containing digits, determine the total number of ways to decode it.
For example,
Given encoded message "12"
, it could be decoded as "AB"
(1 2) or "L"
(12).
The number of ways decoding "12"
is 2.
程序代码:
class Solution {
public:
int numDecodings(string s) {
int n = s.size();
vector<int> f(n + 1, 0);
// 第一位为0则无法解码,输出为0
if (s[0] == '0') {
return 0;
}
// 其余情况f[1] = 1
else {
f[1] = 1;
}
// 前两位在11~19或21~26时,f[2]=2,即前两位可以为一个十位数或两个个位数;
// 第一位为0,或第二位为0且前两位不为10或20时,无法解码,输出0;
// 其余情况f[2] = 1, 即需要将前两位拆成两个个位数.
if ((s[0] == '1' && s[1] != '0') || s[0] == '2' && s[1] <= '6' && s[1] > '0') {
f[2] = 2;
}
else if ((s[0] == '0') || (s[0] != '1' && s[0] != '2' && s[1] == '0')) {
return 0;
}
else {
f[2] = 1;
}
// i从3开始循环,即从字符串第3位(s[2])开始循环,注意s[i-1]对应的是f[i](因为s标号比f小1)
// 当第i个数和第i-1个数组成的数在11~19或21~26时,f[i] = f[i - 1] + f[i - 2];
// 当两个数组成的数为10或20时,f[i] = f[i - 2];
// 当个两个数组成的数不为10或20,且第i个数为0,则无法解码,直接返回结果为0
// 其余情况,即组成01~09或26~99且第i个数不为0时,f[i] = f[i - 1];
for (int i = 3; i <= n; i++) {
if ((s[i - 2] == '1' && s[i - 1] != '0') || s[i - 2] == '2' && s[i - 1] <= '6' && s[i - 1] > '0') {
f[i] = f[i - 1] + f[i - 2];
}
else if ((s[i - 2] == '1' || s[i - 2] == '2') && s[i - 1] == '0') {
f[i] = f[i - 2];
}
else if (s[i - 2] != '1' && s[i - 2] != '2' && s[i - 1] == '0') {
return 0;
}
else {
f[i] = f[i - 1];
}
}
return f[n];
}
};
简要题解:
本题是一道动态规划的问题。
先理清题意。本题的输入是一串数字字符串。从1~26的数字分别解码对应A~Z的字母,需要求出这串输入的数字串共可以有几种解码方法。
令f[i]表示“前i个数字共有几种解码方法”。需要处理的初始值有f[1]和f[2]两种。对于f[1],若第一位为0则无法解码,直接输出为0;其余情况下f[1] = 1。对于f[2],若前两位在11~19或21~26时,f[2]=2,即前两位可以有2种解码方法:为一个十位数或两个个位数;若第一位为0,或第二位为0且前两位不为10或20时,无法解码,直接输出0; 其余情况下均有f[2] = 1, 即前两位只有1种解码方法:需要将前两位拆成两个个位数.
处理完初始值,接着就可以列出转移方程。枚举i = 3 ~ n,注意字符串中s[i-1]对应的是转移方程中的f[i](因为s标号比f小1)。假设已经知道了f[i-1]的值,接着可以分析如下(这部分的思考方法有点类似本周做的台阶问题):
①当第i个数和第i-1个数组成的数在11~19或21~26时,f[i] = f[i - 1] + f[i - 2],即可以将第i个数和i-1个数看作两个1位数(此时对应f[i-1]的值),或是看作一个2位数(此时对应f[i-2]的值);
②当两个数组成的数为10或20时,f[i] = f[i - 2],此时只能将第i和i-1个数看作是一个2位数;
③当个两个数组成的数不为10或20,且第i个数为0,则无法解码,直接返回结果为0;
④其余情况,即组成01~09或26~99且第i个数不为0时,f[i] = f[i - 1],此时只能将第i和i-1个数看作是两个1位数。
这样枚举完之后,就可以计算出各个f[i]的值。
最后的结果即为f[n].
本题是一道稍微复杂的动态规划问题,做本题的关键是,在列出转移方程时,有非常多种不同的情况需要分别考虑。需要仔细认真地进行分类,防止漏掉其中某种转移方程的情况。