算法分析与设计,第16周博客
639. Decode Ways II
A message containing letters from A-Z
is being encoded to numbers using the following mapping way:
'A' -> 1 'B' -> 2 ... 'Z' -> 26
Beyond that, now the encoded string can also contain the character '*', which can be treated as one of the numbers from 1 to 9.
Given the encoded message containing digits and the character '*', return the total number of ways to decode it.
Also, since the answer may be very large, you should return the output mod 109 + 7.
Example 1:
Input: "*" Output: 9 Explanation: The encoded message can be decoded to the string: "A", "B", "C", "D", "E", "F", "G", "H", "I".
Example 2:
Input: "1*" Output: 9 + 9 = 18
Note:
- The length of the input string will fit in range [1, 105].
- The input string will only contain the character '*' and digits '0' - '9'.
暂时先不考虑带有星号的情况。也就是只考虑带有数字的字符串,对于以s[i]结尾的子串,设它可以被解释为dp[i]种解释。那么有:dp[i] = a*dp[i-2] + b*dp[i-1];也就是说,当前的子串和它前两个子串是有关联的:
- 当前字符和前一个字符能被解释能字母时,那么将这两个字符和在一起形成一个整体,在与之前的字符连在一起,就有dp[i-2]种相关的解释方法。
- 当前字符和前一个字符不能被解释成字母是,那么这两个字母便不能合在一起,这时就相当于在之前的字符上多加了一个字符,那么有dp[i-1]种相关的方法。
- s[i] == '*' ,那么就可以代表1-9,这九种情况,所以 b = 9;
- s[i] == '0', 因为映射是从1开始的,所以单独一个0是非法的,所以 b=0;
- '1' <= s[i] <= '9',这些情况下都是合法的,所以 b = 1;
- s[i-1] == '*' && s[i] == '*',两个都是星号。数字可以从11-19、21-26,所以 a = 9+6 = 15;
- s[i-1] == '*',前一个字符为星号,后一个字符不是。在这种情况下,在组成合法数字,那么s[i-1]必定为1或者2,那么就取决于s[i]的情况了。s[i] < '7',此时s[i-1]取1和2都行,所以 a = 2;s[i] >= '7',此时s[i-1]只能取1,所以 a = 1;
- s[i] == '*',前一个字符不是星号,当前字符是。这种情况下,取决于前一个字符。s[i-1] == '1',这种情况下s[i]可以取1-9的任意值,所以 a = 9; s[i-1] == '2',这种情况下,s[i]取1-6之间的任意值,所以 a = 6;其他情况都不能组成合法值,所以 a = 0。
- 两个字符都不是星号,那么要组成合法值必须要在10-26之间,此时 a = 1,其他情况 a = 0 。
class Solution {
public:
int ways(char c) {
if (c == '*')
return 9;
if (c == '0')
return 0;
return 1;
}
int ways(char i, char j) {
if (i == '*' && j == '*')
return 15;
if (i == '*')
return (j <= '6' ? 2 : 1);
if (j == '*') {
if (i == '1')
return 9;
if (i == '2')
return 6;
return 0;
}
if (i == '1' || (i == '2' && j <= '6'))
return 1;
return 0;
}
int numDecodings(string s) {
int n = s.length();
if (n == 0 || s[0] == '0')
return 0;
long frt_2 = 1, frt_1 = ways(s[0]);
long result = frt_1;
long mod = 1000000007;
for (int i = 1; i < n; ++i) {
result = ways(s[i-1], s[i])*frt_2 + ways(s[i])*frt_1;
result = result%mod;
frt_2 = frt_1;
frt_1 = result;
}
return result;
}
};
最后来看下这个算法的时间和空间复杂度,整个代码中没有申请O(n) 数量级的变量,所以空间复杂是O(1)。而其中只用到了一个循环,而循环中每个步骤都是O(1)的时间复杂度,所以总体的时间复杂度是O(n)。