https://leetcode.com/problems/decode-ways/
A message containing letters from A-Z
is being decoded to numbers using the following mapping:
'A' -> 1 'B' -> 2 ... 'Z' -> 26
Given an decoded message containing digits, determine the total number of ways to decode it.
For example,
Given decoded message "12"
, it could be decoded as "AB"
(1 2) or "L"
(12).
The number of ways decoding "12"
is 2.
解题思路:
根据“求解数量用dp,求解集合用dfs”的经验,这题应该用dp来做。
这题有点像走楼梯的题目,定义子状态dp[i]为s.substring(0, i + 1)的decode可能数量。
我们先不考虑s里面含0的情况。如果i和i-1两个字符组成的数字大于27,那么加上i后,不可能有新的decode方法,dp[i]=dp[i - 1]。否则它大于0且小于27,代表还能有一种decode可能,那么dp[i] = dp[i - 1] + dp[i - 2]。
问题是,0的出现使得这道题目比较麻烦。我的方法是,分别考虑i - 1和i是不是0,分四种情况。
1. i - 1 == 0。
1.1 如果i == 0,连续两个0,不可能被decode,直接返回0。
1.2 如果i != 0,dp[i] = dp[i - 1]。
2. i - 1 != 0
2.1 如果i != 0,套用上面的思路。
2.2 如果i == 0,在i - 1 == 1或者i - 1== 2的情况下,dp[i] = dp[i - 2]。否则,i这个地方的0无法和前面一个字符结合,作为从i往后出现的第一个0,也无法被decode,所以直接返回0。
public class Solution { public int numDecodings(String s) { int n = s.length(); if(n == 0) { return 0; } if(s.indexOf("0") == 0) { return 0; } int[] dp = new int[n]; dp[0] = 1; for(int i = 1; i < n; i++) { if(s.charAt(i - 1) == '0') { if(s.charAt(i) != '0') { dp[i] = dp[i - 1]; } else { return 0; } }else { if(s.charAt(i) != '0') { if(Integer.valueOf(s.substring(i - 1, i + 1)) <= 26) { if(i - 2 < 0) { dp[i] = 2; }else { dp[i] = dp[i - 1] + dp[i - 2]; } } else { dp[i] = dp[i - 1]; } } else { if(s.charAt(i - 1) == '1' || s.charAt(i - 1) == '2') { if(i - 2 < 0) { dp[i] = 1; }else { dp[i] = dp[i - 2]; } } else { return 0; } } } } return dp[n - 1]; } }
//20181003
如果i位是0,则它必须要和前一个digit结合,且前一个digit必须是1或者1。一旦结合了,dp[i]就只能等于dp[i] - 2。比如“110”.
如果i不是0,如果它的前一位是1,则他可以和前一位结合,也可以不结合。所以就有两种decode的可能,那么dp[i]=dp[i-1] + dp[i-2]。
如果它的前一位是2,则只有当它是1-6的时候才能和前一位结合,当然也可以不结合。如果大于6,就只能不结合了。
当然,这里所有的情况都还要考虑i==1的情况,因为我们是往前看两位。
class Solution { public int numDecodings(String s) { if (s == null || s.length() == 0) { return 0; } int[] dp = new int[s.length()]; if (s.charAt(0) == '0') { return 0; } dp[0] = 1; for (int i = 1; i < s.length(); i++) { if (s.charAt(i) == '0') { if (s.charAt(i - 1) == '1' || s.charAt(i - 1) == '2') { dp[i] = i == 1 ? 1 : dp[i - 2]; } else { return 0; } } else { if (s.charAt(i - 1) == '1') { dp[i] = i == 1 ? 2 : dp[i - 2] + dp[i - 1]; } else if (s.charAt(i - 1) == '2') { if (s.charAt(i) < '7') { dp[i] = i == 1 ? 2 : dp[i - 2] + dp[i - 1]; } else if (s.charAt(i) > '6') { dp[i] = dp[i - 1]; } } else { dp[i] = dp[i - 1]; } } } return dp[dp.length - 1]; } }