题目链接
题目
动态规划(5步走)
状态表示
dp[i]表示为从下标i之前的的解码数。
状态转移方程
以i位置为终点,下标为i的位置有两种方式:
-
第一种就是单独解码,第二种就是与前面的一位数合并解码。
-
单独解码有分两种情况:第一种是:当s[i]在[1,9]时可以单独解码,就相当于在dp[i-1]种情况后接上一个单独解码,所以dp[i]=dp[i-1],第二种是:当s[i]=0时不可以单独解码。
-
合并解码也分两种情况:第一种:与前面的数合并后的数在[10,26]之间可以合并,就相当于把下标为i-1和i看成一个整体,放在dp[i-2]后,所以dp[i]=dp[i-2];第二种:合并后的数不在[10,26]之间,比如146和100就不可以合并解码,如果第 i 位为0又不可以合并(eg.160、100),就 return 0。因为 i 位为0时说明不可以单独解码也不可以合并,所以就出现了编码错误。
如图:
初始化
初始化的目的是防止越界,所以要使合并时dp[i]=dp[i-2]不越界,至少i=2,所以初始化dp[0]和dp[1]。
填表顺序
从左往右,因为左边的值会对右边产生影响。
返回值
如果没有编码错误返回dp[len-1],否则返回0。
代码
int Getnum(char a,char b)
{
int la=a-48;
int lb=b-48;
return la*10+lb;
}
int numDecodings(char* s) {
int len=strlen(s);
//1.创建dp表
int dp[len];
//2.初始化dp[0]、dp[1]
if(s[0]=='0')
return 0;//出现编码错误
else
{
dp[0]=1;
if(len==1)//不可少,防止dp[1]越界
return 1;
}
if(s[1]>'0'&&s[1]<='9')
{
if(Getnum(s[0],s[1])<=26)
{
//单独解码+合并
dp[1]=2;
}
else
{
//单独解码
dp[1]=1;
}
}
else
{
//为0,只能合并,否则return 0
if(Getnum(s[0],s[1])<=26)
{
//只可以合并
dp[1]=1;
}
else
{
return 0;
}
}
//3.填表。从第3位数开始使用状态方程 i=2
int i=2;
while(i<len)
{
//单独解码+合并解码
if(s[i]>'0'&&s[i]<='9')
{
//可以单独解码
if(Getnum(s[i-1],s[i])>=10&&Getnum(s[i-1],s[i])<=26)
{
//单独解码+合并解码
dp[i]=dp[i-1]+dp[i-2];
}
else
{
//单独解码
dp[i]=dp[i-1];
}
}
else
{
//为0,只可以合并,否则return0
if(Getnum(s[i-1],s[i])>=10&&Getnum(s[i-1],s[i])<=26)
{
//合并解码
dp[i]=dp[i-2];
}
else
{
//不可以合并解码,也不可以单独解码
return 0;
}
}
i++;
}
return dp[len-1];
}
有什么问题可以在评论区@我。