算法设计与分析:Student Attendance Record II(Week 13)

 学号:16340008

题目:552. Student Attendance Record II


Question: 

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  10^9+7

A student attendance record is a string that only contains the following three characters:

 

  1. 'A' : Absent.
  2. 'L' : Late.
  3. 'P' : Present.

 

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.


Answer:

首先我们要考虑将大问题分解成小问题。惯例的,我们用F(N)表示返回结果。

对于一个长度为N的records,我们知道他的结尾可能是A,P,L,于是我们用A(N),P(N),L(N)表示长度为N,结尾分别为A、P、L的字符串。于是我们有等式:

F(N) = A(N) + P(N) + L(N)

先从最简单的入手,我们分解P(N)。P的条件是最少的,没有约束的,对于P结尾的N长串,它的前N-1个字母可以是任意符合条件的(且与结尾是P这一事实无关)。对于P(N)我们有:

P(N) = A(N-1) + P(N-1) + L(N-1)

对于L(N),我们知道它的前N-1项组成的串可以是任意结尾的,但前N-2项组成的则不是。我们用L'(N)表示其以L结尾且下一位(N+1)将是L,对于这样的L'(N),我们可以肯定它的N-1位不能是L。于是我们有式子:

L(N) = A(N-1) + P(N-1) + L'(N-1)

L'(N-1) = A(N-2) + P(N-2)

L(N) = A(N-1) + P(N-1) + A(N-2) + P(N-2)

对于A(N),我们知道它以A结尾,因此它的前N-1项不能有A。我们用L''(N)表示以L结尾的长为N的且没有A的串,P''(N)同理。

于是我们得到式子:

A(N) = P''(N-1) + L''(N-1)

对于P''(N),我们能很轻易得到:

P''(N) = P''(N-1) + L''(N-1)

对于L''(N),与类似L'(N)类似,我们定义一个L'''(N)表示其下一位将为L,以L结尾,长为N,且没有A的串。于是能得到以下式子:

L''(N) = L'''(N-1) + P''(N-1)

L'''(N) = P''(N-1)(显然L'''(N)的N-1位只能为P)

于是有:

L''(N) = P''(N-2) + P''(N-1)

A(N) = P''(N-1) + P''(N-2) + P''(N-3)

P''(N) = P''(N-1) + P''(N-2) + P''(N-3) = A(N)

根据第三条式子我们能轻易得出:

A(N) = A(N-1) + A(N-2) + A(N-3)

综合上面式子中重要的三条:

P(N) = A(N-1) + P(N-1) + L(N-1)

L(N) = A(N-1) + P(N-1) + A(N-2) + P(N-2)

A(N) = A(N-1) + A(N-2) + A(N-3)

现在我们已经得到了递归(或循环)的思路。像其他动态规划一样,直接使用递归将有大量重复的不必要运算。很容易能看出,我们能用三个长为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;
    }
};

leetcode结果:算法设计与分析:Student Attendance Record II(Week 13)_第1张图片 

 

 

 

 

 

你可能感兴趣的:(C语言,算法设计与分析,Python3)