题目
一条包含字母 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) 。
思路1
递归。分为两种情况:选前一个数解码和选前两个数解码。然后将这两种情况解码数加起来。超时。
代码1
class Solution {
public int numDecodings(String s) {
if(s.charAt(0)=='0'){
return 0;
}
if(s.length()==1){
return 1;
}
// 1个
int singlenum=0;
singlenum=numDecodings(s.substring(1));
// 2个
int doublenum=0;
if(Integer.parseInt(s.substring(0,2))>26){
}else{
if(s.length()==2){
doublenum=1;
}else{
doublenum=numDecodings(s.substring(2));
}
}
return singlenum+doublenum;
}
}
思路2
遍历s。List<Integer>记录目前所有解码方式的最后数字。List.size即为所求。
如果当前字符不为'0' :遍历List<Integer>拿到所有解码方式的最后数字与当前字符结合为两位数(或三位数),如果<=26则新增解码方式。并将原解码方式最后数字更新为当前字符。
如果当前字符为'0' :遍历List<Integer>拿到所有解码方式的最后数字与当前字符结合为两位数(或三位数),如果<=26则新增解码方式。并删除错误的解码方式(因为0不能单独作为解码)。
超时。
代码2
class Solution {
public int numDecodings(String s) {
if(s.charAt(0)=='0'){
return 0;
}
List<Integer> l=new ArrayList<Integer>();
l.add(s.charAt(0)-'0');
for(int i=1;i<s.length();i++){
if(s.charAt(i)!='0'){
int lsize=l.size();
for(int j=0;j<lsize;j++){
if( l.get(j)*10 + s.charAt(i)-'0'<= 26){
l.add(l.get(j)*10 + s.charAt(i)-'0');
}
l.set(j,s.charAt(i)-'0');
}
}else{
int lsize=l.size();
for(int j=0;j<lsize;j++){
if( l.get(j)*10 + s.charAt(i)-'0'<= 26){
l.add(l.get(j)*10 + s.charAt(i)-'0');
}
l.set(j,s.charAt(i)-'0');
}
for(int j=0;j<l.size();j++){
if(l.get(j)==0){
l.remove(j);
j--;
}
}
}
}
return l.size();
}
}
思路3
动态规划。int[] res记录当前字符串解码数量。res[res.length-1]即为所求。
初始化res[0]=1。
寻找规律可以发现:
1.当前字符为 '0' : res[i]=res[i-2]
2.前一个字符为'0' : res[i]=res[i-1]
3.当前字符非0: 当前字符与前一个字符组合成两位数。若<=26,则res[i]=res[i-1]+res[i-2];否则res[i]=res[i-1]。
代码3
class Solution {
public int numDecodings(String s) {
if(s.charAt(0)=='0'){
return 0;
}
int[] res=new int[s.length()];
res[0]=1;
for(int i=1;i<s.length();i++){
// 无法解码的情况
if(s.charAt(i)=='0' && s.charAt(i-1)=='0'){
return 0;
}
if(s.charAt(i)=='0' && (s.charAt(i-1)-'0')*10+s.charAt(i)-'0' > 26){
return 0;
}
// 0的情况
if(s.charAt(i)=='0'){
if(i-2>=0){
res[i]=res[i-2];
}else{
res[i]=res[i-1];
}
continue;
}
// 前一个是0的情况
if(s.charAt(i-1)=='0'){
res[i]=res[i-1];
continue;
}
// 非0情况
if( (s.charAt(i-1)-'0')*10+s.charAt(i)-'0' <= 26){
if(i-2>=0){
res[i]=res[i-1]+res[i-2];
}else{
res[i]=res[i-1]*2;
}
}else{
res[i]=res[i-1];
}
}
return res[s.length()-1];
}
}
总结
动态规划比递归快。