(Java) LeetCode 91. Decode Ways —— 解码方法
Posted tengdai
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了(Java) LeetCode 91. 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 a non-empty string containing only digits, determine the total number of ways to decode it.
Example 1:
Input: "12" Output: 2 Explanation: It could be decoded as "AB" (1 2) or "L" (12).
Example 2:
Input: "226" Output: 3 Explanation: It could be decoded as "BZ" (2 26), "VF" (22 6), or "BBF" (2 2 6).
这个题想了好久,觉得真的是比较难想,好多case一遍一遍测试才通过。试着总结一下思路吧。
首先,假如我们分析到了中间,比较通用的情况。
现在在已有字符串的基础上,新来一位字符,就要开始分情况。如果来的是‘0‘,就只有唯一的组成情况,就是和前面的一个数字组成编码,且前面的这个数字还必须是‘1‘或‘2‘,否则就是无效的编码。所以如果来的是‘0‘,相当于要么和前面的数字组合,要么就无效。如果用动态规划的思想,那就先写上伪代码:
if (s[i] == ‘0‘) { if (s[i-1] == ‘1‘ || ‘2‘) dp[i] = dp[i-2]; else return 0; }
这里为什么是dp[i] = dp[i-2]呢?因为‘0‘只能作为和前面的一位字符组合存在,所以前面的字符出现的时候相当于并没有出现,因为它要等着后面的‘0‘来和它组合,所以编码种类和dp[i-2]一样多。
接下来看如果来的是‘1‘~‘9‘,不仅自己要再细分情况,也要再考虑前面一位的情况。如果前面一位是‘1‘,或前一位是‘2‘且这一位是‘1‘~‘6‘,那么可以产生新的编码,因为它既可以独立存在成一个字母,又可以和前面的数字组合形成一个字母。作为独立存在的情况相当于就是取dp[i-1],因为添加一位独立存在的字符并没有增加任何可能性,所以保持和前状态一样;作为组合存在的情况同上,还要再往前想一位。因为如果组合存在的话,前面的一位其实也是和后面的一位作为组合存在而不是独立存在,即当dp[i-1]那位字符来的时候,装作它没来,因为它要等着和后面的字符结合,所以编码种类和dp[i-2]是一样多的。所以最后dp[i] = dp[i-1] + dp[i-2]。
如果前面一位字符不是‘1‘或者‘2‘,那么新来的字符位只能作为独立存在,无法结合。所以并没有产生新的编码可能,即dp[i] = dp[i-1]。
总结起来伪代码如下:
if (s[i-1] == ‘1‘ || (s[i-1] == ‘2‘ && ‘1‘ <= s[i] <= ‘6‘)) dp[i] = dp[i-1] + dp[i-2]; else dp[i] = dp[i-1];
这样所有的情况就分析完了。现在看为了解决通用情况需要些什么,很明显从上面来看,需要知道每一位字符前两位,即dp[0]和dp[1]要首先知道。dp[0]很简单,如果不是‘0‘那就是1,是‘0‘就直接返回0了,第一位是‘0‘无法解码。dp[1]也并不复杂,其实和通用情况一样,如果第二位是‘0‘,dp[1]就是1或return 0,取决于能否和前面结合,即第一位是否是‘1‘或‘2‘;如果第一位是‘1‘,或第一位是‘2‘且第二位是‘1‘~‘6‘,那dp[1]就是2,因为可以结合或独立存在。其他情况就都是1了,因为只能独立存在,不增加解码可能性。
写完了思路发现这道题就写完了,把思路实现即为代码。应该是有很多可以优化的地方,或者是思绪上,或者是代码上,留作以后复习的时候优化吧。现在这么写思路特别清楚,很容易理解,姑且先这样吧!
Java
class Solution { public int numDecodings(String s) { if (s == "") return 0; char[] digit = s.toCharArray(); int[] dp = new int[digit.length]; //get dp[0] dp[0] = digit[0] == ‘0‘ ? 0 : 1; if (dp[0] == 0 || digit.length == 1) return dp[0]; //get dp[1] dp[1] = 1; if (digit[1] == ‘0‘) { if (digit[0] >= ‘3‘) return 0; } else if (digit[0] == ‘1‘ || (digit[0] == ‘2‘ && ‘1‘ <= digit[1] && digit[1] <= ‘6‘)) dp[1] = 2; //get dp[i] for (int i = 2; i < digit.length; i++) { if (digit[i] == ‘0‘) { if (digit[i-1] == ‘1‘ || digit[i-1] == ‘2‘) dp[i] = dp[i-2]; else return 0; } else if (digit[i-1] == ‘1‘ || (digit[i-1] == ‘2‘ && ‘1‘ <= digit[i] && digit[i] <= ‘6‘)) dp[i] = dp[i-1] + dp[i-2]; else dp[i] = dp[i-1]; } return dp[digit.length-1]; } }
以上是关于(Java) LeetCode 91. Decode Ways —— 解码方法的主要内容,如果未能解决你的问题,请参考以下文章
LeetCode第[91]题(Java):Decode Ways(解码方法数)