题目:
A message containing letters from A-Z
is being encoded to numbers using the following mapping:
'A' -> 1 'B' -> 2 ... 'Z' -> 26
Given an encoded message containing digits, determine the total number of ways to decode it.
For example,
Given encoded message "12"
, it could be decoded as "AB"
(1 2) or "L"
(12).
The number of ways decoding "12"
is 2.
链接: http://leetcode.com/problems/decode-ways/
题解:
一看到这题就想到了爬楼梯climb stairs,典型的一维DP。下面就用一维DP来做。先建立数组dp = new int[s.length() + 1], 初始化一个数字的情况dp[0] = 1, 两个数字组成一个两位数字的情况dp[1] = 1。接下来写出循环体,先算一个数字的情况,当s.charAt(i - 1)不为0的时候,dp[i] = dp[i - 1], 否则dp[i] = 0。 接下来考虑两位数字,当由i-2和i-1这两位组成的数字大于等于10,小于等于26时,dp[i] += dp[i - 2], 否则忽略此种情况。
Time Complexity - O(n), Space Complexity - O(n)。
public class Solution { public int numDecodings(String s) { if(s == null || s.length() == 0 || s.charAt(0) == '0') return 0; int[] dp = new int[s.length() + 1]; dp[0] = 1; dp[1] = 1; for(int i = 2; i < dp.length; i++) { int num = Integer.parseInt(s.substring(i - 2, i)); int twoStepsBehind = (num <= 26 && num >= 10) ? dp[i - 2] : 0; int oneStepBehind = s.charAt(i - 1) != '0' ? dp[i - 1] : 0; dp[i] = twoStepsBehind + oneStepBehind; } return dp[s.length()]; } }
可以继续优化Space Complexity至O(1).
public class Solution { public int numDecodings(String s) { if(s == null || s.length() == 0 || s.charAt(0) == '0') return 0; int first = 1; int second = 1; for(int i = 2; i < s.length() + 1; i++) { int num = Integer.parseInt(s.substring(i - 2, i)); int twoStepsBehind = (num >= 10 && num <= 26) ? first : 0; int oneStepBehind = s.charAt(i - 1) != '0' ? second : 0; first = second; second = twoStepsBehind + oneStepBehind; } return second; } }
题外话: 使用DP思想的一些题目 - decode ways, climb stairs, find LCS(longest common subsequence), find longest ascending subsequence, fine longest descending subsequens, 背包问题,poj滑雪,等等。DP这种重要的编程思想要好好学习领会。
二刷:
还是使用dp,新建一个dp数组比较好理解,但空间的优化却不是很熟练。对于dp,还是需要加强狠练。如何才能写出优雅而且精炼的代码是个问题。 Elegant and concise
Java:
Time Complexity - O(n), Space Complexity - O(n)。
public class Solution { public int numDecodings(String s) { if (s == null || s.length() == 0 || s.charAt(0) == '0') { return 0; } int len = s.length(); int[] numWays = new int[len + 1]; numWays[0] = 1; // empty string numWays[1] = 1; // one char for (int i = 2; i <= len; i++) { int num = Integer.parseInt(s.substring(i - 2, i)); numWays[i] = (num <= 26 && num >= 10) ? numWays[i - 2] : 0; numWays[i] += (s.charAt(i - 1) != '0') ? numWays[i - 1] : 0; } return numWays[len]; } }
因为do[i] 只和dp[i - 1]以及dp[i - 2]有关,我们可以优化空间到O(1)。就是使用两个变量来代表numWays[i - 1]和numWays[i - 2], 以及一个变量res来代表它们的和,接下来三个一起倒腾倒腾就好了
Time Complexity - O(n), Space Complexity - O(1)。
public class Solution { public int numDecodings(String s) { if (s == null || s.length() == 0 || s.charAt(0) == '0') { return 0; } int len = s.length(); int lastTwoSteps = 1; // empty string int lastOneStep = 1; // one char int res = 0; for (int i = 2; i <= len; i++) { int num = Integer.parseInt(s.substring(i - 2, i)); res += (num <= 26 && num >= 10) ? lastTwoSteps : 0; res += (s.charAt(i - 1) != '0') ? lastOneStep : 0; lastTwoSteps = lastOneStep; lastOneStep = res; res = 0; } return lastOneStep; } }
题外话:
2/11/2016:
时间相当紧张,要复习LC,刷面经,多线程,设计模式,系统设计。自己提速却不是很成功,转进努力吧。要深入思考。
自己与去年9月开始刷题以来,有什么改变和进步呢??? 好像并没有实质性的突破....要说进步的地方,可能就是养成了学习的习惯吧
Reference:
https://leetcode.com/discuss/49719/dp-with-easy-understand-java-solution
https://leetcode.com/discuss/8527/dp-solution-java-for-reference