学号:16340008
题目:552. Student Attendance Record II
Given a positive integer n, return the number of all possible attendance records with length n, which will be regarded as rewardable. The answer may be very large, return it after mod
A student attendance record is a string that only contains the following three characters:
A record is regarded as rewardable if it doesn't contain more than one 'A' (absent) or more than two continuous 'L' (late).
Example 1:
Input: n = 2
Output: 8
Explanation:
There are 8 records with length 2 will be regarded as rewardable:
"PP" , "AP", "PA", "LP", "PL", "AL", "LA", "LL"
Only "AA" won't be regarded as rewardable owing to more than one absent times.
Note: The value of n won't exceed 100,000.
首先我们要考虑将大问题分解成小问题。惯例的,我们用F(N)表示返回结果。
对于一个长度为N的records,我们知道他的结尾可能是A,P,L,于是我们用A(N),P(N),L(N)表示长度为N,结尾分别为A、P、L的字符串。于是我们有等式:
先从最简单的入手,我们分解P(N)。P的条件是最少的,没有约束的,对于P结尾的N长串,它的前N-1个字母可以是任意符合条件的(且与结尾是P这一事实无关)。对于P(N)我们有:
对于L(N),我们知道它的前N-1项组成的串可以是任意结尾的,但前N-2项组成的则不是。我们用L'(N)表示其以L结尾且下一位(N+1)将是L,对于这样的L'(N),我们可以肯定它的N-1位不能是L。于是我们有式子:
对于A(N),我们知道它以A结尾,因此它的前N-1项不能有A。我们用L''(N)表示以L结尾的长为N的且没有A的串,P''(N)同理。
于是我们得到式子:
对于P''(N),我们能很轻易得到:
对于L''(N),与类似L'(N)类似,我们定义一个L'''(N)表示其下一位将为L,以L结尾,长为N,且没有A的串。于是能得到以下式子:
(显然L'''(N)的N-1位只能为P)
于是有:
根据第三条式子我们能轻易得出:
综合上面式子中重要的三条:
现在我们已经得到了递归(或循环)的思路。像其他动态规划一样,直接使用递归将有大量重复的不必要运算。很容易能看出,我们能用三个长为N的数组记录A(N),L(N),P(N)的元素。从N为1开始自底向上将更清晰。我们需要一些初始数据:
根据上式,A需要A(1)=1,A(2)=2,A(3)=4,L需要L(1)=1,L(2)=3,P需要P(1)=1(穷举)。
得到以下python3代码:
class Solution:
def checkRecord(self, n):
"""
:type n: int
:rtype: int
"""
if n == 1:
return 3
if n == 2:
return 8
mod = 1000000007
A = [0] * n
P = [0] * n
L = [0] * n
A[0] = 1
A[1] = 2
A[2] = 4
L[0] = 1
L[1] = 3
P[0] = 1
for i in range(1, n):
A[i - 1] %= m
P[i - 1] %= m
L[i - 1] %= m
if i > 2:
A[i] = ((A[i-1] + A[i-2]) % mod + A[i-3]) % mod
P[i] = ((A[i-1] + P[i-1]) % mod + L[i-1]) % mod
if i > 1:
L[i] = ((A[i-1] + P[i-1]) % mod + (A[i-2] + P[i-2]) % mod) % mod
return ((A[n-1] + P[n-1]) % mod + L[n-1] % mod) % mod
但是该代码结果超时,于是换成相同原理的C++代码却通过了RTE检验
class Solution {
public:
int checkRecord(int n) {
int mod = 1000000007;
int *A = new int [n];
int *P = new int [n];
int *L = new int [n];
A[0] = 1;
A[1] = 2;
A[2] = 4;
P[0] = 1;
L[0] = 1;
L[1] = 3;
if(n == 1) return 3;
for(int i = 1; i < n; i++)
{
A[i - 1] %= mod;
P[i - 1] %= mod;
L[i - 1] %= mod;
P[i] = ((A[i - 1] + P[i - 1]) % mod + L[i - 1]) % mod;
if(i > 1) L[i] = ((A[i - 1] + P[i - 1]) % mod + (A[i - 2] + P[i - 2]) % mod) % mod;
if(i > 2) A[i] = ((A[i - 1] + A[i - 2]) % mod + A[i - 3]) % mod;
}
return ((A[n - 1] % mod + P[n - 1] % mod) % mod + L[n - 1] % mod) % mod;
}
};