1. 题目描述
难度:中等
2. 题目分析
分析这道题,我们要知道以下几点:
- ‘0’的作用
- ‘0’出现在字符串开头时,肯定是无法编码的,直接返回0;
- 如果字符串中出现‘0’字符并且‘0’字符无法和前面的字符匹配,比如‘30’,‘00’等,肯定也是无法编码的,直接返回0;
- ‘01’不能匹配成1;
- 特殊的边界条件
- 如果输入为空字符串,返回0;
- 如果第一个字符是‘0’, 返回0;
- 如果字符串的长度为1,并且该字符串不是‘0’,返回1;
这道题的解法可以采用动态规划的算法:
- 动态规划
要用动态规划的方法首先要找到动态方程,我们可以根据以下几个条件来进行讨论:- 首先确定dp[0]和dp[1]的值,这很简单,不在赘述;
- 遍历剩余的字符串,并进行分情况讨论:
- 如果s[i] == ‘0’, 并且s[i]和s[i-1]能够匹配成1-26之间的字母,那么动态方程为:
dp[i] = dp[i-2] - 如果s[i] == ‘0’, 并且s[i]和s[i-1]不能够匹配成1-26之间的字母,直接反回0
- 如果s[i] != ‘0’, 并且s[i]和s[i-1]能够匹配成1-26之间的字母,动态方程为:
dp[i] = dp[i-1] + dp[i-2] - 如果s[i] != ‘0’, 并且s[i]和s[i-1]不能够匹配成1-26之间的字母,动态方程为:
dp[i] = dp[i-1]
- 如果s[i] == ‘0’, 并且s[i]和s[i-1]能够匹配成1-26之间的字母,那么动态方程为:
时间复杂度为O(n).
3. C语言实现
代码如下:
// 匹配函数,判断两个字符是否能匹配成1-26之间的字母
int match(char a, char b){
if(a == '0') return 0;
int temp = (a-48)*10 + (b-48);
if(temp<=26 && temp>=1) return 1;
else return 0;
}
int numDecodings(char * s){
int len = strlen(s);
if(len == 0) return 0;
if(s[0]=='0') return 0;
if(len == 1 ) return 1;
int *dp = (int *)malloc(sizeof(int)*len);
dp[0] = 1;
if(match(s[0], s[1])) dp[1] = s[1]=='0'?1:2;
else dp[1] = s[1]=='0'?0:1;
for(int i = 2; i < len; i++){
if(s[i] == '0'){
if(match(s[i-1], s[i])) dp[i] = dp[i-2];
else return 0;
}
else if(match(s[i-1], s[i])) dp[i] = dp[i-1] + dp[i-2];
else dp[i] = dp[i-1];
}
return dp[len-1];
}
运行结果为: