Decode Ways

A message containing letters from A-Z is being encoded to numbers using the following mapping:

'A' -> 1
'B' -> 2
...
'Z' -> 26

Given an encoded message containing digits, determine the total number of ways to decode it.

For example,
Given encoded message "12", it could be decoded as "AB" (1 2) or "L" (12).

The number of ways decoding "12" is 2.

这是个DP问题,最关键的就是找到状态转移方程,但这个状态转移方程还真难住了,想到一个果断敲进去,发现错了,就一筹莫展。百度了下,结果也全是直接给的大同小异的代码,转移方程的产生过程没有一个提起。这也难怪,都是大牛,我等菜鸟望尘莫及。想不出来我们可以写个最规范的例子来画一画,至于特殊的情况我们不去考虑先。

尽管我们不知道状态转移方程的确切形式,但是我们总应该想到用f[ i ] 来表示前 i 个字符的解码方法数。这就足够了。


这里得到的状态转移方程虽然是理想情况下的,但是毕竟我们还是发现了其中的规律,s[ i ]跟 s[ i - 1]构成的关系分为以下几种:

1)s[ i ] 可以独立存在,即可以被单独解码,而且s[ i ] 跟前面的字符组合后形成的组合数也可以被解码,即也是合法的编码。

2)s[ i ] 可以独立存在,即可以被单独解码,但是不能跟前面的字符组合形成组合数,即组合数的编码非法,不能被解析。

3)s[ i ] 不能独立存在,这只有一种情况,就是s[ i ] 为 ‘0’的时候,但可以依附前面的字符,形成组合数,构成合法编码。

4)s[ i ] 不能独立存在,而且也不能跟前面的字符形成组合数,这时,就是错误的编码,无法解析。

那么我们看下,在这些情况下我们的状态方程是什么样的。

1)这当然是我们在上图表中发现的完美规律了,f [ i ] = f [ i - 1] + f [ i  - 2]

2)这种情况就是我们在图表中总结的第1点,所以这时 f[ i ] = f [ i - 1]

3)这种情况就是我们在图表中总结的第 2 点,这时 f [ i ] = f [ i - 2]  

好了,问题分析到这里,我想大家都跃跃欲试了,差不多,可以开始了,至于怎么判断合法不合法,每个人的判断方法不同,实现也就不太一样,但这无关紧要,最关键的是我们分析清楚状态转移方程。

注意:

1.这里我们在设定状态的时候,因为 关系到 f[ i  - 2] ,所以我们还是多开几个空间为好。

2.判断下s[ 0 ],若为‘0’ 就返回吧。

//CODE

class Solution {
public:
	int numDecodings(string s) {
		vector<int> dp(s.size() + 3, 1);
		if(s.size() == 0 || s[0] == '0') return 0;
		for(int i = 1; i < s.size(); ++i)
		{
	        // i start from 0, j start from 1.
			int j = i + 1;

	//(1):s[i]这个0既不能独立存在,也跟前面的结合不了,不能解析。
			if(s[i] == '0' && (s[i - 1] == '0' || s[i - 1] > '2')) 
				return 0;

	//(2):s[i]这个0虽然不能独立存在,但是可以傍上s[i-1]这个大款,形成组合数。
			else if(s[i] == '0') dp[j] = dp[j - 2];

	//(3):s[i]可以独立存在,但是无法与前面的s[i-1]结合,构成组合数。
			else if(s[i-1] == '0'|| s[i - 1] > '2' 
				|| s[i - 1] == '2' && s[i] > '6')
				dp[j] = dp[j - 1];

	//(4):s[i]可以独立存在,也可以与前面的s[i - 1]组成结合数。
			else
			    dp[j] = dp[j - 1] + dp[j - 2];
			//独立存在:可以被解析。 
			//构成组合数:组合数可以被解析。
		}
		return dp[s.size()];
	}
};


 // http://blog.csdn.net/shiquxinkong, 转载请说明出处。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值