题目描述
一条包含字母 A-Z 的消息通过以下方式进行了编码:
‘A’ -> 1
‘B’ -> 2
…
‘Z’ -> 26
给定一个只包含数字的非空字符串,请计算解码方法的总数。
示例 1:
输入: “12”
输出: 2
解释: 它可以解码为 “AB”(1 2)或者 “L”(12)。
示例 2:
输入: “226”
输出: 3
解释: 它可以解码为 “BZ” (2 26), “VF” (22 6), 或者 “BBF” (2 2 6) 。
题目分析
就以例子中的226来看。首先判断2是否为0以及是否为小于26,如果满足条件那么方法数+1,接着看22,也满足加1,接着看第二个2,发现满足加1。从这个可以看出来只要开始遍历,分别看单数字和与后面一个数字的组合,判断是否满足条件即可,满足就加1不满足就下一个。那么这样就可以用递归做了。
源码
class Solution {
private int count = 0;
public int numDecodings(String s) {
if(s.length() == 0) return 0;
char[] cs = s.toCharArray();
int[] a = new int[cs.length];
for(int i = 0;i < cs.length;i++){
a[i] = cs[i] - '0';
}
//先将字符串转换成整数类型的数组
dfs(a,0,a[0]);
return count;
}
public void dfs(int[] a,int idx,int num){
if(num == 0 || num > 26) return;
// num不能为0,不能大于26
// 到达末尾,判断num是否合法
if(idx == a.length - 1) {
if(num <= 26) count++;
return;
}
dfs(a,idx + 1,a[idx + 1]);
// 单个数字为一组
dfs(a,idx + 1,num * 10 + a[idx + 1]);
// 和后一个数字为一组
}
}
改进
事实证明,当我提交的时候时间600ms的我惊呆了,竟然这么慢,不过确实两次递归不慢才怪了相当于遍历了两遍数组,时间的复杂度就上升到了O(m^2)。那就应该换一种方法来降低复杂度,从上面的推理可能还看不出什么,那么下面就用更长一点的字符串来展示一下。以2331231216为例吧,这个肯定够长了。
从0开始,0为索引值。
2成立+1,23成立+1;
3成立+1,33不成立保持+1;
3成立+1,31不成立保持+1;
1成立+1,12成立+1……
可以看出来count是怎么加的呢?
如果dp[n-1]满足条件就为1,10*dp[n-2]+dp[n-1]满足条件就再加1
可以从我的表达式看出来,这就是用动态规划了。
为什么用n-1 呢,因为前两个为初始状态,所以要从第2个开始,这样就能保持空间复杂度为O(1)了
改进代码
class Solution {
public int numDecodings(String s) {
int n = s.length();
int[] dp = new int[n+1];
//dp数组用来保存是否满足条件
if(s.charAt(0)!='0')
dp[1] = dp[0] = 1;
for(int i = 2;i<=n;i++){
if(s.charAt(i-1)=='0'){
if(s.charAt(i-2)=='1' || s.charAt(i-2)=='2')
dp[i] = dp[i-2];
else
return 0;
}
else{
dp[i] = dp[i-1];
if(s.charAt(i-2)!='0'){
int t = 10*(s.charAt(i-2)-'0')+s.charAt(i-1)-'0';
if(t<=26)
dp[i] += dp[i-2];
}
}
}
return dp[n];
}
}
分析
第一个时间复杂度为O(m^2)
第二个就是O(n)
空间复杂度都为O(1)
[1]https://leetcode-cn.com/problems/decode-ways/submissions/