leetcode 随笔 Decode Ways & Decode Ways II --动态规划

终于写完项目了,今天开始恢复每日LeetCode的练习。关于项目的总结,这两天尽量写一篇总结的博客,遇到的问题还是挺多的,尤其是在发布的时候,各种莫名其妙的bug。感谢室友的帮助,最后总算是赶出来了。

下面还是看看新的LeetCode题目,不知道是不是好久不写了,今天这两题都没做出来 ̄□ ̄||,好好整理一下。

Decode Ways

原题链接

这题上来我的思路就是递归,先递归再说,最后面临长字符串的输入出现了时间超限。

看到discuss里的动态规划的思路,感到豁然开朗。

我们假设一个输入的字符串,.......123......,我们挑中间一段数,不管前后


r2意思是解码到这个位置的可能性的个数,r1的位置意思解码到1这个位置可能性的个数

因为2这个位置这里可以解码为... +"12"+... 也可以解码为 ...+"1"+"2"+...所以一共有r1+r2种

动态规划的更新就很明显了。

class Solution {
public:
	int numDecodings(string s) {
		if (s.empty() || s[0] == '0') return 0;
		int *record = new int[s.size()+1];
		memset(record, 0, sizeof(int)*(1+s.size()));
		record[0] = 1; record[1] = 1;
		for (int i = 1; i < s.size(); i++)
		{
			if (s[i] == '0')
			{
				record[i] = 0;
			}
			if (s[i - 1] == '1' ||( s[i - 1] == '2' && s[i] <= '6'))
			{
				record[i+1] = record[i - 1] + record[i];
			}
			else
			{
				record[i + 1] = record[i];
			}
		}
		return record[s.size()];
	}
};

代码中有一个record数组,record[i+1]记录解码到第i位置的方法数。

我们也会发现其实用到这个数组的地方只有数组的开始两位,因此可以简化至如下:(代码来自Discuss)

class Solution {
public:
	int numDecodings(string s) {
		if (!s.size() || s.front() == '0') return 0;
		// r2: decode ways of s[i-2] , r1: decode ways of s[i-1] 
		int r1 = 1, r2 = 1;

		for (int i = 1; i < s.size(); i++) {
			// zero voids ways of the last because zero cannot be used separately
			if (s[i] == '0') r1 = 0;

			// possible two-digit letter, so new r1 is sum of both while new r2 is the old r1
			if (s[i - 1] == '1' || s[i - 1] == '2' && s[i] <= '6') {
				r1 = r2 + r1;
				r2 = r1 - r2;
			}

			// one-digit letter, no new way added
			else {
				r2 = r1;
			}
		}

		return r1;
	}
};

++++++++++++++++++++++++++++++++++++++++++++++++++++++++

++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 Decode Ways II

原题链接

比起上一题,多了正则的部分,其实也就是多了几种情况,只是情况比较复杂也容易出现疏漏。举两个例子:


首先看这种情况,这种情况可以是从r1那直接接过来,也可以是从r2那接过来,*的表示范围是从1-9

所以 ?= r1 + 2*r2



这种情况下,?=r1+ 9*r2


(代码from discuss)

class Solution {
public:
    int numDecodings(string s) {
        int n = s.size(), p = 1000000007;
        // f2 is the answer to sub string ending at position i; Initially i = 0.
        long f1 = 1, f2 = helper(s.substr(0,1));
        // DP to get f2 for sub string ending at position n-1;
        for (int i = 1; i < n; i++) {
            long f3 = (f2*helper(s.substr(i, 1)))+(f1*helper(s.substr(i-1, 2)));
            f1 = f2;
            f2 = f3%p;
        }
        return f2;
    }
private:
    int helper(string s) {
        if (s.size() == 1) {
            if (s[0] == '*') return 9;
            return s[0] == '0'? 0:1;
        }
        // 11-26, except 20 because '*' is 1-9
        if (s == "**")  
            return 15;
        else if (s[1] =='*') {
            if (s[0] =='1') return 9;
            return s[0] == '2'? 6:0;
        }
        else if (s[0] == '*') 
            return s[1] <= '6'? 2:1;
        else 
            // if two digits, it has to be in [10 26]; no leading 0
            return stoi(s) >= 10 && stoi(s) <= 26? 1:0; 
    }
};


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值