[dp] LeetCode 91. Decode Ways

输入:一个字符串,只包含0-9的字符。
输出:解码种类
规则:有一种信息映射规则 A->1,B->2…Z->26。
例如输入’1’,只能解码为A。
输入’12’,可以解码为’AB’,也可以是’L’,有2种解码方式。
分析:这一个分析思路很自然,但是很麻烦,最后还是有逻辑漏洞。
向这种多阶段完成的题目已经做过很多,不假思索就是这样想的。
如果需要解码’12128’这个字符串,
如果只有1,一种解法:A
如果是12,可以看做1+2,也可以看做12。解码就是A+B,或者L。
如果是121,可以看做是12+1,也可以看做是1+21。
 如果是12+1,解法种类等于12的解法:2。
 如果是1+21,解法种类等于1的解法:1。
 最终结果是3。
如果是1212,可以看做是121+2,也可以看做是12+12。
 如果是121+2,解法种类等于121的解法:3。
 如果是12+12,解法种类等于12的解法:2。
 最终结果是5。
如果是12127,可以看做是1212+7,也可以看做是121+27?错了,27没有对应的字母,所以只有1212+7这一种。
 如果是1212+7,解法种类等于1212的解法:5。
看到这里其实动态转移方程已经出来了。

dp[i]=dp[i-1]+dp[i-2],这是当Number(i-1,i)<=26的时候。
dp[i]=dp[i-1] 这是当Number(i-1,i)>26的时候。

对0字符还没有考虑,0没有对应的字母,那结果是怎样的?
对于’012’,因为0没有对应直接返回0。
对于’102’,可以分解为10+2两个部分,解码为’JB’,答案为1。
对于’100’,分解为10+0不对,0没有映射,分解为1+00,同样不对,0还是没有映射。所以答案为0。
对于’1002’,同样没法分解。答案 为0。
也就是说如果0在第0位,答案为0;如果(前一位+0)可以合并成一个大于0且 小雨等于26的数,那解法种类和前一位相同。如果不是,那答案为0。

分析2:从后往前看。参考链接

例子依然是字符串’12128’
8:解法总数(8)=1
28:2+8,解法总数(28)=解法总数(8)
128:1+count(‘28’),或者12+8,解法总数(128)=解法总数(28)+解法 总数(8)
2128: 2+128;21+count(28),解法总数(2128)=解法总数(128)+解法 总数(28)

字符串’012’
2
12: 12 或者 1+2
012:0和谁都不能分到一起解码,所以为0。

字符串 ‘100’
0:答案0
00 :答案 0
100:答案 0 因为前两步都是0

字符串’1002’

当字符中包含0,对于当前位置不等于0的来说,number(i,i+1)<=26的话,解法总数(i)=解法总数(i+1)+解法总数(i+2),和上面的规则是相符 的。这样来考虑就简单了许多。
这样从后向前考虑问题,以及对于0的处理,都是要学习的地方 。

	public int numDecodings(String s) {
        if(s==null || s.length()==0 ) return 0;
        int  n = s.length();
        int[] dp = new int[n+1];
        dp[n] = 1;
        dp[n-1] = s.charAt(n-1)=='0'?0:1;
        for(int i=n-2;i>=0;i--){
            if(s.charAt(i)=='0'){
                dp[i] = 0;
            }else if((s.charAt(i)-'0')*10 + (s.charAt(i+1)-'0')<=26){
                dp[i] = dp[i+1]+dp[i+2];
            }else{
                dp[i] = dp[i+1];
            }
            
        }
        return dp[0];
    }
发布了148 篇原创文章 · 获赞 35 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/flying_all/article/details/103774797