LeetCode-----第九十一题-----解码方法

解码方法

难度:中等

一条包含字母 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) 。

 

题目分析:

       做完之后才知道,这题为啥通过率这么低。这个0是真的恶心。1.当0和前面的数组合大于26时就无效返回0;2.当连续出现0的时候无效返回0;3.当0和出现在首位的时候无效,返回0.这题显然用DP。

       1.状态转换方程是:1)当s[i] == 0的时候:

                                           f[i] = f[i-2] (因为0和前面一个数字进行了绑定)

                                       2)当s[i] != 0的时候:

                                         f[i] = f[i-1] + f[i-2] (在当前值和前面一个值组合小于等于26的时候);

                                         f[i] = f[i-1] (当前值和前面一个值组合大于26时)

       2.数据结构选择一维数组

       3.初始化,注意0可能出现在第一和第二位。当没有0出现时,f[0] = 1,f[1]和f[0]的组合大于等于26时,f[1] = 1,否则 f[1] =2;

       4,遍历填表。很关键的是要分析0的情况(具体见代码)

 

参考代码:

class Solution {
public:
	int numDecodings(string s) {
		if (s.empty())
			return s.size();

		vector<int> f;
		f.resize(s.size());
        //首位为0,返回0;否则初始化
		if (s[0] == '0')
			return 0;
		else
			f[0] = 1;
        //必须要判断,否则如果只有一位,下面的s[1]会越界
		if (s.size() == 1)
			return 1;
        //第二位不为0,如果和s[0]组合小于等于26,f[1] = 2,否则f[1] = 1
        //第二位为0,如果前面那位大于2,就是无效数组,返回0
		if (s[1] != '0' && (s[0] - '0') * 10 + s[1] - '0' <= 26)
			f[1] = 2;
		else if (s[1] == '0' && !(s[0] == '1' || s[0] == '2'))
			return 0;
		else
			f[1] = 1;
		int temp = 0;
        //从第三个数开始遍历,大致分三种情况
		for (int i = 2; i < s.size(); i++)
		{
            //当前值为0,前面的值为1或者2,有效,当前的总数等于前面第二位
			if (s[i] == '0' && (s[i - 1] == '1' || s[i - 1] == '2'))
				f[i] = f[i - 2];
            //当前值为0,前面的值不为1或者2,无效
			else if (s[i] == '0' && !(s[i - 1] == '1' || s[i - 1] == '2'))
				return 0;
            //当前值不为0的情况,需要判断前面那个值为不为0
			else if (s[i] > '0' && s[i] <= '9')
			{
                //前面的值不为0,正常判断
				if (s[i - 1] != '0')
				{
					temp = (s[i - 1] - '0') * 10 + s[i] - '0';

					if (temp <= 26)
						f[i] = f[i - 1] + f[i - 2];
					else
						f[i] = f[i - 1];
				}
				else{//前面的值为0,当前的总数等于前面第二位
					f[i] = f[i - 2];
				}
			}
		}
		return f[s.size() - 1];
	}
};

 

参考代码:(上面那种情况分的太复杂了,看看这个)

class Solution {
public:
	int numDecodings(string s) {
        //如果空字符串或者开局为0,那不好意思直接返回0(失效)
		if (s.empty() || s[0] == '0')
			return 0;
        
        //只有一个字符的话就直接返回1吧
		if (s.size() == 1)
			return 1;
		vector<int> f(s.size() + 1, 0);//这里多申请一个单位内存,后边有用

		s = "0" + s;//为了方便计算,最前面加个“0”字符
        //初始化一下,前面两个字符对应的数为1
		f[0] = 1;
		f[1] = 1;
		for (int i = 2; i < s.size(); i++) //从第三个字符开始(加“0”后)
		{
            //先计算一波当前位置和前面一位组成的数
			int temp = (s[i - 1] - '0') * 10 + s[i] - '0';
            //先考虑当前字符为“0”(0字符贼坑)
			if (s[i] == '0')
			{
                //如果前一个字符也为“0”或者和前面字符不能组成10,20(都是无效情况)
				if (s[i - 1] == '0' || temp > 26)
					return 0;
				else
                    //或者就等于f[i - 2],如果不是这么操作的话,遇到110这种情况就会算错
					f[i] = f[i - 2];
			}
			else{//当前字符不是“0”字符
                //如果前一个字符等于“0”,或者两个字符组合大于26,就等于前面一个就行
				if (s[i - 1] == '0' || temp > 26)
					f[i] = f[i - 1];
				else//如果组合数是在(10,26]之间,那么相加
					f[i] = f[i - 1] + f[i - 2];
			}
		}
		return f[s.size()-1];
	}
};

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值