动态规划,dp[i]代表字符串s.substr(0, i) decode ways的数量.
注意到0只能在10,20中出现,亦即字符串包含0时,前面的数字只能为1或2.
1) 当s[i]为0时
若s[i-1]不为1或2, 直接返回0;
若s[i-1]为1或1, dp[i] = dp[i-1]
2) 当s[i]不为0时
若s[i-1]为0, dp[i] = dp[i-1].
若i+1<s.size(), s[i+1]为0, dp[i] = dp[i-1]. (语义是当前这个数只能后面的0组成一个数,而这个数是否合法(为10或20), 则交由考察s[i+1]时判定)
若string_to_int(s.substr(i-1, 2))<=26, dp[i] = dp[i-1] + dp[i-2] (此时可将s[i-1]和s[i-2]看成一个字符,那么有dp[i-2]种可能;或仍当做单独的两个字符,那么有dp[i-1]种可能)
其他情况,dp[i] = dp[i-1].
代码:
class Solution
{
public:
int numDecodings(string s)
{
if ( s.empty() )
{
return 0;
} else if ( s[0] == '0' )
{
return 0;
} else if ( s.size() == 1)
{
return 1;
}
vector<int> dp(s.size(), 1);
if (s[1] == '0')
{
if (s[0]!='1' && s[0]!='2')
{
return 0;
} else
{
dp[1] = dp[0];
}
} else
{
if (2<s.size() && s[2]=='0')
{
dp[1] = dp[0];
} else
{
dp[1] = dp[0] + (string_to_int(s.substr(0, 2))<=26? 1: 0);
}
}
for (size_t i = 2; i < s.size(); ++ i)
{
if (s[i]=='0')
{
if (s[i-1]!='1' && s[i-1]!='2')
{
return 0;
} else
{
dp[i] = dp[i-1];
}
} else // 自身非0
{
if (s[i-1] == '0')
{
dp[i] = dp[i-1];
} else if (i+1<s.size() && s[i+1]=='0')
{
dp[i] = dp[i-1];
} else
{
dp[i] = dp[i-1] + (string_to_int(s.substr(i-1, 2))<=26? dp[i-2]: 0);
}
}
}
return dp.back();
}
private:
int string_to_int(const string& s)
{
int ret;
stringstream ss;
ss << s;
ss >> ret;
return ret;
}
};