输入:一个字符串,只包含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。
看到这里其实动态转移方程已经出来了。
当s[i] !=0 的时候:
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。也就是0在首位,直接返回0。
对于’10’,可以分解为10+2两个部分,解码为’JB’,答案为1。
对于’210’,可以分解为2+10两个部分,分解数量和’2’是一样的,也就是dp[i] = dp[i-2]。
对于’280’,没有分解策略,应该返回0。
对于’100’,分解为10+0不对,0没有映射,分解为1+00,同样不对,0还是没有映射。应该直接返回0。
当s[i] ==0的时候:
if Number(i-1,1)<=26,那么dp[i] = dp[i-2]。
if Number(i-1,1)>26,则返回0。
if 两个连续的0挨着,则返回0。
if 0在第0个位置,则无效,返回0。
这道题目和爬楼梯是一个类型,只是有更多的限制条件。需要将各种情况思考一遍。参考链接。
public int numDecodings(String s) {if(s==null || s.length()==0 ) return 0;int n = s.length();int[] dp = new int[n];if(s.charAt(0)=='0') return 0;dp[0] = 1;if(n>1){if(s.charAt(1)=='0'){if(s.charAt(0)=='0'){return 0;}else if((s.charAt(0) - '0')*10 + (s.charAt(1) - '0')<=26){dp[1] = dp[0];}else{return 0;}}else{dp[1] = (s.charAt(0) - '0')*10 + (s.charAt(1) - '0')<=26?dp[0]+1:1;} }for(int i =2;i<n;i++){if(s.charAt(i)=='0'){if(s.charAt(i-1)!='0' && (s.charAt(i-1) - '0')*10 + (s.charAt(i) - '0')<=26){dp[i] = dp[i-2];}else {return 0;}}else{if(s.charAt(i-1)=='0'){dp[i] = dp[i-1];}else if( (s.charAt(i-1) - '0')*10 + (s.charAt(i) - '0')<=26){dp[i] = dp[i-1] +dp[i-2];}else{dp[i] = dp[i-1] ;}}}return dp[n-1];}
分析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];}