分析:粗看这道题时感觉很麻烦,因为在题目中二十六个字母不仅对应着一位数,还对应着两位数并且还要考虑0存在时的特殊情况,这使得解题变的非常困难。但是当我们仔细观察后发现这道题并没有想象中的那么难,它的核心解题思想和LeetCode-70爬楼梯这道题十分相似,而爬楼梯这道题的核心解题思路在之前已经写过,下面是这道题的核心思想。
核心思想:依旧从结果开始分析。我们用n表示在字符串s中第n(n>2)个字符,f(n)表示n及以前的字符的组合方式总数,我们知道第n个字符的组合方式只有三种。1.与前面的数字组成一个两位数。2.与后面的数字组成一个两位数。3.自己单独形成一个数字。但是在一次循环中我们只需要考虑1,3两种情况就可以了,应为2的一个会在下一次循环中包括。所以我们先看稍微简单的第三种情况,第n个字符单独作为一个数字:我们从高中的数学知识可以看出其方法总数就是前n个字符的方法总数f(n-1)。我们再看第一种情况与前面的数字形成一个二位数:与第三种情况的思路相同可以得到这时的方法总数就是f(n-2)。所以综合上面的两种情况我们可以的到n个字符的方法总数有
这个公式再LeetCode-70爬楼梯就已经得出来过,但是如果光用这一个公式时无法解出这道题的。因为不是每一个数字都能与前面的数字组成一个二位数,也不是每一个数字能够单独成为一个数字。所以当只能单独成为一个数字时的方法总数有
只能组成一个两位数组的方法总数有
所以我们就可以看出来两道题的核心思想的不同之处也就在这里了,我们再写代码的时候我们就需要进行判断,然后选择相对应的公式进行计算,而且我们通过字符串的前两个字符的判断也很容易得到前两个数字的方法数,我们只需要再循环中进行循环的相加和判断就可以得出结果了。下面的代码的书写过程。
由于个f(n)只与f(n-1)和f(n-2)有关,所以我们在循环中只能从n=3的时候开始计算,所以我们就需要先把f(1)和f(2)计算出来,计算f(1)和f(2)的代码如下
char temp1=s.charAt(0);
char temp2=s.charAt(1);//前两个字符
int number1=1;//字符数只有1时的方法总数肯定只有1
int number2;//字符数2时的方法总数,暂时无法确定
if(temp1=='1'&&temp2!='0'||temp1=='2'&&temp2>'0'&&temp2<='6')//当十位为1时个位为任意数字或者当十位数为2个位数必须要小于等于6时可以组成两位数
{
number2=2;
}
else if(temp1>'2'&&temp2=='0')//此时数字无法形成两位数也无法形成一个单独的一位数
{
return 0;
}
else
{
number2=1;
}//其他情况下只能组成一位数(确定两位数的方法总数)
值得注意的是在这里存在这一个无法形成两位数也无法形成一个单独的一位数的特殊情况,这种情况就是当第一个数字大于2且第二个数字等于0和第一个数字等于0时,这样的话方法数就直接为0,直接返回0就可以了(第一个数字为0的情况在前面会进行排除,这里就无需进行排除)。
然后就是循环结构中的书写了,循环结构的代码如下
int answer=0;
for(int i=2;i<s.length();i++)
{
char temp=s.charAt(i);
temp2=s.charAt(i-1);
//判断i字符能否和i-1字符组成一个两位数,判断方法与上面相同
if(temp=='0'&&temp2=='0'||temp=='0'&&temp2>'2')
{
return 0;
}
if(temp2=='1'&&temp!='0'||temp2=='2'&&temp>'0'&&temp<='6')
{
answer=number1+number2;
}
else if(temp=='0')//此时只能组成两位数
{
answer=number1;
}
else
{
answer=number2;
}
number1=number2;
number2=answer;
这里多了一个无法为个位数字也无法成为两位数字的特殊情况,就是两个0相邻,这样的方法数也直接为0,直接返回就行了。
然后我们在考虑一下字符串s的长度为1和为2的两种特殊情况就可以将这道题解出了,下面是完整代码
class Solution
{
public int numDecodings(String s)
{
if(s.charAt(0)=='0')//首位为0的特殊情况,直接将0截去
{
return 0;
}
if(s.length()==1)
{
return 1;
}//当长度为1时的特殊情况只有一种方法
else
{
char temp1=s.charAt(0);
char temp2=s.charAt(1);//前两个字符
int number1=1;//字符数只有1时的方法总数肯定只有1
int number2;//字符数2时的方法总数,暂时无法确定
if(temp1=='1'&&temp2!='0'||temp1=='2'&&temp2>'0'&&temp2<='6')//当十位为1时个位为任意数字或者当十位数为2个位数必须要小于等于6时可以组成两位数
{
number2=2;
}
else if(temp1>'2'&&temp2=='0')//此时数字无法形成两位数也无法形成一个单独的一位数
{
return 0;
}
else
{
number2=1;
}//其他情况下只能组成一位数(确定两位数的方法总数)
if(s.length()==2)
{
return number2;
}//字符串长度为2的特殊情况直接返回number2
else
{
int answer=0;
for(int i=2;i<s.length();i++)
{
char temp=s.charAt(i);
temp2=s.charAt(i-1);
//判断i字符能否和i-1字符组成一个两位数,判断方法与上面相同
if(temp=='0'&&temp2=='0'||temp=='0'&&temp2>'2')
{
return 0;
}
if(temp2=='1'&&temp!='0'||temp2=='2'&&temp>'0'&&temp<='6')
{
answer=number1+number2;
}
else if(temp=='0')//此时只能组成两位数
{
answer=number1;
}
else
{
answer=number2;
}
number1=number2;
number2=answer;
}
return answer;
}
}
}
}