LeetCode-Decode Ways II
来源:互联网 发布:二次元网络漫画图片 编辑:程序博客网 时间:2024/06/07 18:05
算法分析与设计,第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: 9Explanation: 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]种相关的方法。
所以,对于每一个字符,都只需要找出与之相关的系数a和b,就可以确定dp[i]。
那么,接下来考虑带有星号的情况。
首先来确定比较简单的系数b的情况,因为b是不能与之前的字符组成合法解释,所以只需要考虑这个字符本身即可:
- s[i] == '*' ,那么就可以代表1-9,这九种情况,所以 b = 9;
- s[i] == '0', 因为映射是从1开始的,所以单独一个0是非法的,所以 b=0;
- '1' <= s[i] <= '9',这些情况下都是合法的,所以 b = 1;
接下来讨论系数a的情况,这种情况下,当前字符与之前的字符组合形成代码,所以需要考虑两个字符。按照星号的分布,有以下几种情况:
- 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 。
解决完这两个系数的问题后,整个问题就基本得到了解决,不过仍需要注意的是,因为结果可能比较大,会超出int的数值范围,所以可能需要用到long的数值类型,总体的代码如下:
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)。
阅读全文